diff --git a/Cargo.lock b/Cargo.lock index 46ad7ac..29f0e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,15 +330,24 @@ dependencies = [ "fake 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gotham_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gotham_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "h2" version = "0.1.26" @@ -966,6 +975,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_derive" @@ -1474,6 +1486,7 @@ dependencies = [ "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum gotham 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb734995f768833f633d6acaee1fe768e1395dafc75362a2dac404ba32d7883a" +"checksum gotham_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b207d2aa120b2d7be4bb7edc48b199297ebce4227979127b0879890a84163480" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" diff --git a/Cargo.toml b/Cargo.toml index 9461cd3..f8071bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,10 @@ gitlab = { repository = "msrd0/gotham-restful", branch = "master" } failure = "0.1" futures = "0.1" gotham = "0.4" +gotham_derive = "0.4" hyper = "0.12" mime = "0.3" -serde = "1" -serde_derive = "1" +serde = { version = "1", features = ["derive"] } serde_json = "1" [dev-dependencies] diff --git a/examples/users.rs b/examples/users.rs index d73e7b3..c736721 100644 --- a/examples/users.rs +++ b/examples/users.rs @@ -1,6 +1,4 @@ -extern crate log; -#[macro_use] -extern crate serde_derive; +#[macro_use] extern crate serde; use fake::{faker::internet::en::Username, Fake}; use gotham::{ @@ -9,7 +7,7 @@ use gotham::{ router::builder::*, state::State }; -use gotham_restful::{DrawResources, DrawResourceRoutes, IndexResource, Resource, Success}; +use gotham_restful::{DrawResources, DrawResourceRoutes, GetResource, IndexResource, Resource, Success}; use log::LevelFilter; use log4rs::{ append::console::ConsoleAppender, @@ -37,11 +35,21 @@ impl IndexResource>> for Users } } +impl GetResource> for Users +{ + fn get(_state : &mut State, id : u64) -> Success + { + let username : String = Username().fake(); + User { username: format!("{}{}", username, id) }.into() + } +} + impl Resource for Users { fn setup(mut route : D) { route.index::<_, Self>(); + route.get::<_, _, Self>(); } } diff --git a/src/lib.rs b/src/lib.rs index d167d18..05a9345 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ -#[macro_use] -extern crate serde_derive; +#[macro_use] extern crate gotham_derive; +#[macro_use] extern crate serde; pub use hyper::StatusCode; @@ -8,7 +8,7 @@ pub use resource::{ Resource, IndexResource, GetResource, - PostResource + CreateResource }; mod result; diff --git a/src/resource.rs b/src/resource.rs index 62c007f..a823e80 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -1,23 +1,31 @@ use crate::{DrawResourceRoutes, ResourceResult}; use gotham::state::State; use serde::de::DeserializeOwned; +use std::panic::RefUnwindSafe; +/// This trait must be implemented by every RESTful Resource. It will +/// allow you to register the different methods for this Resource. pub trait Resource { fn setup(route : D); } +/// Handle a GET request on the Resource root. pub trait IndexResource { fn index(state : &mut State) -> R; } -pub trait GetResource +/// Handle a GET request on the Resource with an id. +pub trait GetResource +where + ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static { - fn get(state : State, id : ID) -> dyn ResourceResult; + fn get(state : &mut State, id : ID) -> R; } -pub trait PostResource +/// Handle a POST request on the Resource root. +pub trait CreateResource { - fn post(state : State, body : Body) -> dyn ResourceResult; + fn post(state : &mut State, body : Body) -> R; } diff --git a/src/routing.rs b/src/routing.rs index a38ab09..40cb650 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -1,15 +1,23 @@ -use crate::{IndexResource, Resource, ResourceResult}; +use crate::{GetResource, IndexResource, Resource, ResourceResult}; use futures::future::{err, ok}; use gotham::{ handler::{HandlerFuture, IntoHandlerError}, helpers::http::response::create_response, pipeline::chain::PipelineHandleChain, router::builder::*, - state::State + state::{FromState, State} }; use mime::APPLICATION_JSON; +use serde::de::DeserializeOwned; use std::panic::RefUnwindSafe; +/// Allow us to extract an id from a path. +#[derive(Deserialize, StateData, StaticResponseExtender)] +struct PathExtractor +{ + id : ID +} + /// This trait adds the `resource` method to gotham's routing. It allows you to register /// any RESTful `Resource` with a path. pub trait DrawResources @@ -21,7 +29,16 @@ pub trait DrawResources /// `Resource::setup` method. pub trait DrawResourceRoutes { - fn index>(&mut self); + fn index(&mut self) + where + R : ResourceResult, + IR : IndexResource; + + fn get(&mut self) + where + ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static, + R : ResourceResult, + IR : GetResource; } fn to_handler_future(mut state : State, get_result : F) -> Box @@ -44,6 +61,17 @@ fn index_handler>(state : State) -> Bo to_handler_future(state, |state| IR::index(state)) } +fn get_handler>(state : State) -> Box +where + ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static +{ + let id = { + let path : &PathExtractor = PathExtractor::borrow_from(&state); + path.id.clone() + }; + to_handler_future(state, |state| GR::get(state, id)) +} + macro_rules! implDrawResourceRoutes { ($implType:ident) => { impl<'a, C, P> DrawResources for $implType<'a, C, P> @@ -62,10 +90,24 @@ macro_rules! implDrawResourceRoutes { C : PipelineHandleChain

+ Copy + Send + Sync + 'static, P : RefUnwindSafe + Send + Sync + 'static { - /// Register an `IndexResource` with this resource. - fn index>(&mut self) + fn index(&mut self) + where + R : ResourceResult, + IR : IndexResource { - self.0.get(&self.1).to(|state| index_handler::(state)); + self.0.get(&self.1) + .to(|state| index_handler::(state)); + } + + fn get(&mut self) + where + ID : DeserializeOwned + Clone + RefUnwindSafe + Send + Sync + 'static, + R : ResourceResult, + IR : GetResource + { + self.0.get(&format!("{}/:id", self.1)) + .with_path_extractor::>() + .to(|state| get_handler::(state)); } } }