From df7ffe14f23806a1621ca9bb147ea4442c26cf72 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 28 Mar 2018 11:20:06 -0700 Subject: [PATCH] add PathAndQuery extractor --- src/extractor.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 +- 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/extractor.rs b/src/extractor.rs index 8700ee3b6..3fcbeeae2 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -26,7 +26,7 @@ pub trait HttpRequestExtractor: Sized where T: DeserializeOwned, S: 'stati /// # extern crate actix_web; /// # extern crate futures; /// #[macro_use] extern crate serde_derive; -/// use actix_web::*; +/// # use actix_web::*; /// use actix_web::Path; /// /// /// Application state @@ -113,7 +113,7 @@ impl HttpRequestExtractor for Path /// # extern crate actix_web; /// # extern crate futures; /// #[macro_use] extern crate serde_derive; -/// use actix_web::*; +/// # use actix_web::*; /// use actix_web::Query; /// /// /// Application state @@ -189,6 +189,110 @@ impl HttpRequestExtractor for Query } } +/// Extract typed information from from the request's path and query. +/// +/// `S` - application state type +/// +/// ## Example +/// +/// ```rust +/// # extern crate bytes; +/// # extern crate actix_web; +/// # extern crate futures; +/// #[macro_use] extern crate serde_derive; +/// # use actix_web::*; +/// use actix_web::PathAndQuery; +/// +/// /// Application state +/// struct State {} +/// +/// #[derive(Deserialize)] +/// struct PathParam { +/// username: String, +/// } +/// +/// #[derive(Deserialize)] +/// struct QueryParam { +/// count: u32, +/// } +/// +/// // use `with` extractor for query info +/// // this handler get called only if request's path contains `username` field +/// // and query contains `count` field +/// fn index(data: PathAndQuery) -> Result { +/// Ok(format!("Welcome {}!", data.path().username)) +/// } +/// +/// fn main() { +/// let app = Application::with_state(State{}).resource( +/// "/index.html", +/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor +/// } +/// ``` +pub struct PathAndQuery{ + pitem: P, + qitem: Q, + req: HttpRequest, +} + +impl PathAndQuery { + + /// Path information + #[inline] + pub fn path(&self) -> &P { + &self.pitem + } + + /// Query information + #[inline] + pub fn query(&self) -> &Q { + &self.qitem + } + + /// Shared application state + #[inline] + pub fn state(&self) -> &S { + self.req.state() + } + + /// Incoming request + #[inline] + pub fn request(&self) -> &HttpRequest { + &self.req + } + + /// Deconstruct instance into a parts + pub fn into(self) -> (P, Q, HttpRequest) { + (self.pitem, self.qitem, self.req) + } +} + +impl HttpRequestExtractor for PathAndQuery + where T: de::DeserializeOwned, Q: de::DeserializeOwned, S: 'static +{ + type Result = FutureResult; + + #[inline] + fn extract(req: &HttpRequest) -> Self::Result { + let req = req.clone(); + + let qitem = match serde_urlencoded::from_str::(req.query_string()) + .map_err(|e| e.into()) + { + Ok(item) => item, + Err(err) => return result(Err(err)) + }; + let pitem = match de::Deserialize::deserialize(PathExtractor{req: &req}) + .map_err(|e| e.into()) + { + Ok(item) => item, + Err(err) => return result(Err(err)) + }; + + result(Ok(PathAndQuery{pitem, qitem, req})) + } +} + macro_rules! unsupported_type { ($trait_fn:ident, $name:expr) => { fn $trait_fn(self, _: V) -> Result diff --git a/src/lib.rs b/src/lib.rs index be7b2fd9d..1f3af3b6e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,7 +145,7 @@ pub use route::Route; pub use resource::Resource; pub use context::HttpContext; pub use server::HttpServer; -pub use extractor::{Path, Query}; +pub use extractor::{Path, PathAndQuery, Query}; // re-exports pub use http::{Method, StatusCode, Version};