diff --git a/gotham_restful/src/result.rs b/gotham_restful/src/result.rs index 610b8f3..6fb889b 100644 --- a/gotham_restful/src/result.rs +++ b/gotham_restful/src/result.rs @@ -1,6 +1,7 @@ use crate::{ResourceType, StatusCode}; #[cfg(feature = "openapi")] use crate::{OpenapiSchema, OpenapiType}; +use hyper::Body; use mime::{Mime, APPLICATION_JSON}; #[cfg(feature = "openapi")] use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty}; @@ -8,41 +9,54 @@ use serde::Serialize; use serde_json::error::Error as SerdeJsonError; use std::error::Error; +/// A response, used to create the final gotham response from. pub struct Response { pub status : StatusCode, - pub body : String, + pub body : Body, pub mime : Option } impl Response { - pub fn new(status : StatusCode, body : String, mime : Option) -> Self + /// Create a new `Response` from raw data. + pub fn new>(status : StatusCode, body : B, mime : Option) -> Self { Self { status, - body, + body: body.into(), mime } } - pub fn json(status : StatusCode, body : String) -> Self + /// Create a `Response` with mime type json from already serialized data. + pub fn json>(status : StatusCode, body : B) -> Self { Self { status, - body, + body: body.into(), mime: Some(APPLICATION_JSON) } } + /// Create a _204 No Content_ `Response`. pub fn no_content() -> Self { Self { status: StatusCode::NO_CONTENT, - body: String::new(), + body: Body::empty(), mime: None } } + + #[cfg(test)] + fn full_body(self) -> Vec + { + 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. @@ -50,7 +64,7 @@ pub trait ResourceResult { /// Turn this into a response that can be returned to the browser. This api will likely /// change in the future. - fn to_response(&self) -> Result; + fn into_response(self) -> Result; /// Return a list of supported mime types. fn accepted_types() -> Option> @@ -98,10 +112,10 @@ impl From for ResourceError impl ResourceResult for Result { - fn to_response(&self) -> Result + fn into_response(self) -> Result { 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) => { let err : ResourceError = e.into(); Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?) @@ -158,7 +172,7 @@ impl From for Success impl ResourceResult for Success { - fn to_response(&self) -> Result + fn into_response(self) -> Result { Ok(Response::json(StatusCode::OK, serde_json::to_string(&self.0)?)) } @@ -208,7 +222,7 @@ impl From<()> for NoContent impl ResourceResult for NoContent { /// This will always be a _204 No Content_ together with an empty string. - fn to_response(&self) -> Result + fn into_response(self) -> Result { Ok(Response::no_content()) } @@ -230,10 +244,10 @@ impl ResourceResult for NoContent impl ResourceResult for Result { - fn to_response(&self) -> Result + fn into_response(self) -> Result { match self { - Ok(nc) => nc.to_response(), + Ok(nc) => nc.into_response(), Err(e) => { let err : ResourceError = e.into(); Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)) @@ -268,11 +282,11 @@ impl Raw } } -impl ResourceResult for Raw +impl> ResourceResult for Raw { - fn to_response(&self) -> Result + fn into_response(self) -> Result { - 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")] @@ -290,10 +304,10 @@ impl ResourceResult for Result, E> where Raw : ResourceResult { - fn to_response(&self) -> Result + fn into_response(self) -> Result { match self { - Ok(raw) => raw.to_response(), + Ok(raw) => raw.into_response(), Err(e) => { let err : ResourceError = e.into(); Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)) @@ -331,50 +345,50 @@ mod test fn resource_result_ok() { let ok : Result = 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.body, r#"{"msg":""}"#); assert_eq!(res.mime, Some(APPLICATION_JSON)); + assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes()); } #[test] fn resource_result_err() { let err : Result = 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.body, format!(r#"{{"error":true,"message":"{}"}}"#, err.unwrap_err())); assert_eq!(res.mime, Some(APPLICATION_JSON)); + assert_eq!(res.full_body(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes()); } #[test] fn success_always_successfull() { let success : Success = 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.body, r#"{"msg":""}"#); assert_eq!(res.mime, Some(APPLICATION_JSON)); + assert_eq!(res.full_body(), r#"{"msg":""}"#.as_bytes()); } #[test] fn no_content_has_empty_response() { 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.body, ""); assert_eq!(res.mime, None); + assert_eq!(res.full_body(), &[] as &[u8]); } #[test] fn no_content_result() { let no_content : Result = 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.body, ""); assert_eq!(res.mime, None); + assert_eq!(res.full_body(), &[] as &[u8]); } #[test] @@ -382,9 +396,9 @@ mod test { let msg = "Test"; 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.body, msg); assert_eq!(res.mime, Some(TEXT_PLAIN)); + assert_eq!(res.full_body(), msg.as_bytes()); } } diff --git a/gotham_restful/src/routing.rs b/gotham_restful/src/routing.rs index 400dfa8..437c282 100644 --- a/gotham_restful/src/routing.rs +++ b/gotham_restful/src/routing.rs @@ -131,7 +131,7 @@ where F : FnOnce(&mut State) -> R, R : ResourceResult { - let res = get_result(&mut state).to_response(); + let res = get_result(&mut state).into_response(); match res { Ok(res) => { 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 { Ok(res) => { let r = response_from(res, &state);