1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-04-19 22:44:38 +00:00

use Into<hyper::Body> for Response

This commit is contained in:
Dominic 2019-10-20 00:36:00 +02:00
parent 9e9b8869c9
commit 3a03dc60fa
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
2 changed files with 46 additions and 32 deletions

View file

@ -1,6 +1,7 @@
use crate::{ResourceType, StatusCode}; use crate::{ResourceType, StatusCode};
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use crate::{OpenapiSchema, OpenapiType}; use crate::{OpenapiSchema, OpenapiType};
use hyper::Body;
use mime::{Mime, APPLICATION_JSON}; use mime::{Mime, APPLICATION_JSON};
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty}; use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty};
@ -8,41 +9,54 @@ use serde::Serialize;
use serde_json::error::Error as SerdeJsonError; use serde_json::error::Error as SerdeJsonError;
use std::error::Error; use std::error::Error;
/// A response, used to create the final gotham response from.
pub struct Response pub struct Response
{ {
pub status : StatusCode, pub status : StatusCode,
pub body : String, pub body : Body,
pub mime : Option<Mime> pub mime : Option<Mime>
} }
impl Response impl Response
{ {
pub fn new(status : StatusCode, body : String, mime : Option<Mime>) -> Self /// Create a new `Response` from raw data.
pub fn new<B : Into<Body>>(status : StatusCode, body : B, mime : Option<Mime>) -> Self
{ {
Self { Self {
status, status,
body, body: body.into(),
mime mime
} }
} }
pub fn json(status : StatusCode, body : String) -> Self /// Create a `Response` with mime type json from already serialized data.
pub fn json<B : Into<Body>>(status : StatusCode, body : B) -> Self
{ {
Self { Self {
status, status,
body, body: body.into(),
mime: Some(APPLICATION_JSON) mime: Some(APPLICATION_JSON)
} }
} }
/// Create a _204 No Content_ `Response`.
pub fn no_content() -> Self pub fn no_content() -> Self
{ {
Self { Self {
status: StatusCode::NO_CONTENT, status: StatusCode::NO_CONTENT,
body: String::new(), body: Body::empty(),
mime: None mime: None
} }
} }
#[cfg(test)]
fn full_body(self) -> Vec<u8>
{
use futures::{future::Future, stream::Stream};
let bytes : &[u8] = &self.body.concat2().wait().unwrap().into_bytes();
bytes.to_vec()
}
} }
/// A trait provided to convert a resource's result to json. /// A trait provided to convert a resource's result to json.
@ -50,7 +64,7 @@ pub trait ResourceResult
{ {
/// Turn this into a response that can be returned to the browser. This api will likely /// Turn this into a response that can be returned to the browser. This api will likely
/// change in the future. /// change in the future.
fn to_response(&self) -> Result<Response, SerdeJsonError>; fn into_response(self) -> Result<Response, SerdeJsonError>;
/// Return a list of supported mime types. /// Return a list of supported mime types.
fn accepted_types() -> Option<Vec<Mime>> fn accepted_types() -> Option<Vec<Mime>>
@ -98,10 +112,10 @@ impl<T : ToString> From<T> for ResourceError
impl<R : ResourceType, E : Error> ResourceResult for Result<R, E> impl<R : ResourceType, E : Error> ResourceResult for Result<R, E>
{ {
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
Ok(match self { Ok(match self {
Ok(r) => Response::json(StatusCode::OK, serde_json::to_string(r)?), Ok(r) => Response::json(StatusCode::OK, serde_json::to_string(&r)?),
Err(e) => { Err(e) => {
let err : ResourceError = e.into(); let err : ResourceError = e.into();
Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?) Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)
@ -158,7 +172,7 @@ impl<T> From<T> for Success<T>
impl<T : ResourceType> ResourceResult for Success<T> impl<T : ResourceType> ResourceResult for Success<T>
{ {
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
Ok(Response::json(StatusCode::OK, serde_json::to_string(&self.0)?)) Ok(Response::json(StatusCode::OK, serde_json::to_string(&self.0)?))
} }
@ -208,7 +222,7 @@ impl From<()> for NoContent
impl ResourceResult for NoContent impl ResourceResult for NoContent
{ {
/// This will always be a _204 No Content_ together with an empty string. /// This will always be a _204 No Content_ together with an empty string.
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
Ok(Response::no_content()) Ok(Response::no_content())
} }
@ -230,10 +244,10 @@ impl ResourceResult for NoContent
impl<E : Error> ResourceResult for Result<NoContent, E> impl<E : Error> ResourceResult for Result<NoContent, E>
{ {
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
match self { match self {
Ok(nc) => nc.to_response(), Ok(nc) => nc.into_response(),
Err(e) => { Err(e) => {
let err : ResourceError = e.into(); let err : ResourceError = e.into();
Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)) Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?))
@ -268,11 +282,11 @@ impl<T> Raw<T>
} }
} }
impl<T : ToString> ResourceResult for Raw<T> impl<T : Into<Body>> ResourceResult for Raw<T>
{ {
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
Ok(Response::new(StatusCode::OK, self.raw.to_string(), Some(self.mime.clone()))) Ok(Response::new(StatusCode::OK, self.raw, Some(self.mime.clone())))
} }
#[cfg(feature = "openapi")] #[cfg(feature = "openapi")]
@ -290,10 +304,10 @@ impl<T, E : Error> ResourceResult for Result<Raw<T>, E>
where where
Raw<T> : ResourceResult Raw<T> : ResourceResult
{ {
fn to_response(&self) -> Result<Response, SerdeJsonError> fn into_response(self) -> Result<Response, SerdeJsonError>
{ {
match self { match self {
Ok(raw) => raw.to_response(), Ok(raw) => raw.into_response(),
Err(e) => { Err(e) => {
let err : ResourceError = e.into(); let err : ResourceError = e.into();
Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)) Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?))
@ -331,50 +345,50 @@ mod test
fn resource_result_ok() fn resource_result_ok()
{ {
let ok : Result<Msg, MsgError> = Ok(Msg::default()); let ok : Result<Msg, MsgError> = Ok(Msg::default());
let res = ok.to_response().expect("didn't expect error response"); let res = ok.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.body, r#"{"msg":""}"#);
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes());
} }
#[test] #[test]
fn resource_result_err() fn resource_result_err()
{ {
let err : Result<Msg, MsgError> = Err(MsgError::default()); let err : Result<Msg, MsgError> = Err(MsgError::default());
let res = err.to_response().expect("didn't expect error response"); let res = err.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(res.body, format!(r#"{{"error":true,"message":"{}"}}"#, err.unwrap_err()));
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes());
} }
#[test] #[test]
fn success_always_successfull() fn success_always_successfull()
{ {
let success : Success<Msg> = Msg::default().into(); let success : Success<Msg> = Msg::default().into();
let res = success.to_response().expect("didn't expect error response"); let res = success.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.body, r#"{"msg":""}"#);
assert_eq!(res.mime, Some(APPLICATION_JSON)); assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes());
} }
#[test] #[test]
fn no_content_has_empty_response() fn no_content_has_empty_response()
{ {
let no_content = NoContent::default(); let no_content = NoContent::default();
let res = no_content.to_response().expect("didn't expect error response"); let res = no_content.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::NO_CONTENT); assert_eq!(res.status, StatusCode::NO_CONTENT);
assert_eq!(res.body, "");
assert_eq!(res.mime, None); assert_eq!(res.mime, None);
assert_eq!(res.full_body(), &[] as &[u8]);
} }
#[test] #[test]
fn no_content_result() fn no_content_result()
{ {
let no_content : Result<NoContent, MsgError> = Ok(NoContent::default()); let no_content : Result<NoContent, MsgError> = Ok(NoContent::default());
let res = no_content.to_response().expect("didn't expect error response"); let res = no_content.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::NO_CONTENT); assert_eq!(res.status, StatusCode::NO_CONTENT);
assert_eq!(res.body, "");
assert_eq!(res.mime, None); assert_eq!(res.mime, None);
assert_eq!(res.full_body(), &[] as &[u8]);
} }
#[test] #[test]
@ -382,9 +396,9 @@ mod test
{ {
let msg = "Test"; let msg = "Test";
let raw = Raw::new(msg, TEXT_PLAIN); let raw = Raw::new(msg, TEXT_PLAIN);
let res = raw.to_response().expect("didn't expect error response"); let res = raw.into_response().expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK); assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.body, msg);
assert_eq!(res.mime, Some(TEXT_PLAIN)); assert_eq!(res.mime, Some(TEXT_PLAIN));
assert_eq!(res.full_body(), msg.as_bytes());
} }
} }

View file

@ -131,7 +131,7 @@ where
F : FnOnce(&mut State) -> R, F : FnOnce(&mut State) -> R,
R : ResourceResult R : ResourceResult
{ {
let res = get_result(&mut state).to_response(); let res = get_result(&mut state).into_response();
match res { match res {
Ok(res) => { Ok(res) => {
let r = response_from(res, &state); let r = response_from(res, &state);
@ -170,7 +170,7 @@ where
} }
}; };
let res = get_result(&mut state, body).to_response(); let res = get_result(&mut state, body).into_response();
match res { match res {
Ok(res) => { Ok(res) => {
let r = response_from(res, &state); let r = response_from(res, &state);