diff --git a/gotham_restful/src/lib.rs b/gotham_restful/src/lib.rs index 727eca9..fe8a1f0 100644 --- a/gotham_restful/src/lib.rs +++ b/gotham_restful/src/lib.rs @@ -76,7 +76,10 @@ extern crate self as gotham_restful; #[macro_use] extern crate gotham_derive; #[macro_use] extern crate serde; -pub use hyper::StatusCode; +#[doc(no_inline)] +pub use hyper::{Chunk, StatusCode}; +#[doc(no_inline)] +pub use mime::Mime; pub use gotham_restful_derive::*; diff --git a/gotham_restful/src/routing.rs b/gotham_restful/src/routing.rs index 22ed134..d587e38 100644 --- a/gotham_restful/src/routing.rs +++ b/gotham_restful/src/routing.rs @@ -27,6 +27,7 @@ use gotham::{ use hyper::{ header::CONTENT_TYPE, Body, + HeaderMap, Method }; use mime::{Mime, APPLICATION_JSON}; @@ -144,7 +145,7 @@ where fn handle_with_body(mut state : State, get_result : F) -> Box where - Body : DeserializeOwned, + Body : RequestBody, F : FnOnce(&mut State, Body) -> R + Send + 'static, R : ResourceResult { @@ -156,8 +157,16 @@ where Ok(body) => body, Err(e) => return err((state, e.into_handler_error())) }; + + let content_type : Mime = match HeaderMap::borrow_from(&state).get(CONTENT_TYPE) { + Some(content_type) => content_type.to_str().unwrap().parse().unwrap(), + None => { + let res = create_empty_response(&state, StatusCode::UNSUPPORTED_MEDIA_TYPE); + return ok((state, res)) + } + }; - let body = match serde_json::from_slice(&body) { + let body = match Body::from_body(body, content_type) { Ok(body) => body, Err(e) => return { let error : ResourceError = e.into(); diff --git a/gotham_restful/src/types.rs b/gotham_restful/src/types.rs index 9e34add..e0198bc 100644 --- a/gotham_restful/src/types.rs +++ b/gotham_restful/src/types.rs @@ -1,6 +1,8 @@ #[cfg(feature = "openapi")] -use crate::OpenapiType; +use crate::{OpenapiType, result::ResourceError}; +use hyper::Chunk; +use mime::{Mime, APPLICATION_JSON}; use serde::{de::DeserializeOwned, Serialize}; #[cfg(not(feature = "openapi"))] @@ -39,10 +41,31 @@ impl ResponseBody for T /// A type that can be used inside a request body. Implemented for every type that is /// deserializable with serde. If the `openapi` feature is used, it must also be of type /// `OpenapiType`. -pub trait RequestBody : ResourceType + DeserializeOwned +pub trait RequestBody : ResourceType + Sized { + type Err : Into; + + /// Return all types that are supported as content types + fn supported_types() -> Option> + { + None + } + + /// Create the request body from a raw body and the content type. + fn from_body(body : Chunk, content_type : Mime) -> Result; } impl RequestBody for T { + type Err = serde_json::Error; + + fn supported_types() -> Option> + { + Some(vec![APPLICATION_JSON]) + } + + fn from_body(body : Chunk, _content_type : Mime) -> Result + { + serde_json::from_slice(&body) + } }