diff --git a/examples/users.rs b/examples/users.rs index c736721..bcda16e 100644 --- a/examples/users.rs +++ b/examples/users.rs @@ -1,3 +1,4 @@ +#[macro_use] extern crate log; #[macro_use] extern crate serde; use fake::{faker::internet::en::Username, Fake}; @@ -7,7 +8,7 @@ use gotham::{ router::builder::*, state::State }; -use gotham_restful::{DrawResources, DrawResourceRoutes, GetResource, IndexResource, Resource, Success}; +use gotham_restful::*; use log::LevelFilter; use log4rs::{ append::console::ConsoleAppender, @@ -17,7 +18,7 @@ use log4rs::{ struct Users; -#[derive(Serialize)] +#[derive(Deserialize, Serialize)] struct User { username : String @@ -44,12 +45,22 @@ impl GetResource> for Users } } +impl CreateResource> for Users +{ + fn create(_state : &mut State, body : User) -> Success<()> + { + info!("Created User: {}", body.username); + ().into() + } +} + impl Resource for Users { fn setup(mut route : D) { route.index::<_, Self>(); route.get::<_, _, Self>(); + route.create::<_, _, Self>(); } } diff --git a/src/resource.rs b/src/resource.rs index a823e80..15bdb9f 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -27,5 +27,5 @@ where /// Handle a POST request on the Resource root. pub trait CreateResource { - fn post(state : &mut State, body : Body) -> R; + fn create(state : &mut State, body : Body) -> R; } diff --git a/src/routing.rs b/src/routing.rs index 40cb650..4a159ee 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -1,5 +1,16 @@ -use crate::{GetResource, IndexResource, Resource, ResourceResult}; -use futures::future::{err, ok}; +use crate::{ + result::ResourceError, + CreateResource, + GetResource, + IndexResource, + Resource, + ResourceResult, + StatusCode +}; +use futures::{ + future::{Future, err, ok}, + stream::Stream +}; use gotham::{ handler::{HandlerFuture, IntoHandlerError}, helpers::http::response::create_response, @@ -34,11 +45,17 @@ pub trait DrawResourceRoutes R : ResourceResult, IR : IndexResource; - fn get(&mut self) + fn get(&mut self) where ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static, R : ResourceResult, - IR : GetResource; + GR : GetResource; + + fn create(&mut self) + where + Body : DeserializeOwned, + R : ResourceResult, + CR : CreateResource; } fn to_handler_future(mut state : State, get_result : F) -> Box @@ -56,6 +73,49 @@ where } } +fn handle_with_body(mut state : State, get_result : F) -> Box +where + Body : DeserializeOwned, + F : FnOnce(&mut State, Body) -> R + Send + 'static, + R : ResourceResult +{ + let f = hyper::Body::take_from(&mut state) + .concat2() + .then(|body| { + + let body = match body { + Ok(body) => body, + Err(e) => return err((state, e.into_handler_error())) + }; + + let body = match serde_json::from_slice(&body) { + Ok(body) => body, + Err(e) => return { + let error : ResourceError = e.into(); + match serde_json::to_string(&error) { + Ok(json) => { + let res = create_response(&state, StatusCode::BAD_REQUEST, APPLICATION_JSON, json); + ok((state, res)) + }, + Err(e) => err((state, e.into_handler_error())) + } + } + }; + + let res = get_result(&mut state, body).to_json(); + match res { + Ok((status, body)) => { + let res = create_response(&state, status, APPLICATION_JSON, body); + ok((state, res)) + }, + Err(e) => err((state, e.into_handler_error())) + } + + }); + + Box::new(f) +} + fn index_handler>(state : State) -> Box { to_handler_future(state, |state| IR::index(state)) @@ -72,6 +132,11 @@ where to_handler_future(state, |state| GR::get(state, id)) } +fn create_handler>(state : State) -> Box +{ + handle_with_body::(state, |state, body| CR::create(state, body)) +} + macro_rules! implDrawResourceRoutes { ($implType:ident) => { impl<'a, C, P> DrawResources for $implType<'a, C, P> @@ -109,6 +174,16 @@ macro_rules! implDrawResourceRoutes { .with_path_extractor::>() .to(|state| get_handler::(state)); } + + fn create(&mut self) + where + Body : DeserializeOwned, + R : ResourceResult, + CR : CreateResource + { + self.0.post(&self.1) + .to(|state| create_handler::(state)); + } } } }