use bytes::Bytes;
use futures_core::Stream;
use http::header::{CONTENT_LENGTH, CONTENT_TYPE, TRANSFER_ENCODING};
use http::{HeaderName, HeaderValue, StatusCode, Version};
use http_body::Frame;
use http_body_util::StreamBody;
use serde::Serialize;
use super::Response;
use super::body::ResponseBody;
use crate::error::Error;
pub trait Finalize {
fn finalize(self, response: ResponseBuilder) -> Result<Response, Error>;
}
#[derive(Debug, Default)]
pub struct ResponseBuilder {
response: http::response::Builder,
}
#[derive(Serialize)]
struct JsonData<T> {
data: T,
}
#[derive(Serialize)]
struct JsonErrors {
errors: [Error; 1],
}
impl ResponseBuilder {
#[inline]
pub fn status<T>(mut self, status: T) -> Self
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<http::Error>,
{
self.response = self.response.status(status);
self
}
#[inline]
pub fn version(mut self, version: Version) -> Self {
self.response = self.response.version(version);
self
}
#[inline]
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
{
self.response = self.response.header(key, value);
self
}
#[inline]
pub fn extension<T>(mut self, extension: T) -> Self
where
T: Clone + Send + Sync + 'static,
{
self.response = self.response.extension(extension);
self
}
#[inline]
pub fn body(self, body: ResponseBody) -> Result<Response, Error> {
Ok(self.response.body(body)?.into())
}
#[inline]
pub fn data<T>(self, data: T) -> Result<Response, Error>
where
T: Serialize,
{
self.json(&JsonData { data })
}
#[inline]
pub fn errors(self, error: Error) -> Result<Response, Error> {
self.json(&JsonErrors { errors: [error] })
}
#[inline]
pub fn json(self, body: &impl Serialize) -> Result<Response, Error> {
match serde_json::to_vec(body) {
Ok(body) => self
.header(CONTENT_LENGTH, body.len())
.header(CONTENT_TYPE, "application/json; charset=utf-8")
.body(ResponseBody::from(body)),
Err(error) => Err(Error::from_serde_json(
StatusCode::INTERNAL_SERVER_ERROR,
error,
)),
}
}
#[inline]
pub fn html(self, body: impl Into<String>) -> Result<Response, Error> {
let body = body.into();
self.header(CONTENT_LENGTH, body.len())
.header(CONTENT_TYPE, "text/html; charset=utf-8")
.body(ResponseBody::from(body))
}
#[inline]
pub fn text(self, body: impl Into<String>) -> Result<Response, Error> {
let body = body.into();
self.header(CONTENT_LENGTH, body.len())
.header(CONTENT_TYPE, "text/plain; charset=utf-8")
.body(ResponseBody::from(body))
}
#[inline]
pub fn finish(self) -> Result<Response, Error> {
self.body(ResponseBody::default())
}
}
impl<T> Finalize for T
where
T: Stream<Item = Result<Frame<Bytes>, Error>> + Send + Sync + 'static,
{
#[inline]
fn finalize(self, builder: ResponseBuilder) -> Result<Response, Error> {
builder
.header(TRANSFER_ENCODING, "chunked")
.body(ResponseBody::boxed(StreamBody::new(self)))
}
}