mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-31 11:02:08 +01:00
added State extractor
This commit is contained in:
parent
d24752d9bc
commit
3e98177fad
@ -33,7 +33,7 @@ Actix web is a simple, pragmatic, extremely fast, web framework for Rust.
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate actix_web;
|
extern crate actix_web;
|
||||||
use actix_web::*;
|
use actix_web::{Application, HttpServer, Path};
|
||||||
|
|
||||||
fn index(info: Path<(String, u32)>) -> String {
|
fn index(info: Path<(String, u32)>) -> String {
|
||||||
format!("Hello {}! id:{}", info.0, info.1)
|
format!("Hello {}! id:{}", info.0, info.1)
|
||||||
|
105
src/de.rs
105
src/de.rs
@ -12,8 +12,6 @@ use httprequest::HttpRequest;
|
|||||||
|
|
||||||
/// Extract typed information from the request's path.
|
/// Extract typed information from the request's path.
|
||||||
///
|
///
|
||||||
/// `S` - application state type
|
|
||||||
///
|
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -49,66 +47,48 @@ use httprequest::HttpRequest;
|
|||||||
/// # use actix_web::*;
|
/// # use actix_web::*;
|
||||||
/// use actix_web::Path;
|
/// use actix_web::Path;
|
||||||
///
|
///
|
||||||
/// /// Application state
|
|
||||||
/// struct State {}
|
|
||||||
///
|
|
||||||
/// #[derive(Deserialize)]
|
/// #[derive(Deserialize)]
|
||||||
/// struct Info {
|
/// struct Info {
|
||||||
/// username: String,
|
/// username: String,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /// extract path info using serde
|
/// /// extract path info using serde
|
||||||
/// fn index(info: Path<Info, State>) -> Result<String> {
|
/// fn index(info: Path<Info>) -> Result<String> {
|
||||||
/// Ok(format!("Welcome {}!", info.username))
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::with_state(State{}).resource(
|
/// let app = Application::new().resource(
|
||||||
/// "/{username}/index.html", // <- define path parameters
|
/// "/{username}/index.html", // <- define path parameters
|
||||||
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Path<T, S=()>{
|
pub struct Path<T>{
|
||||||
item: T,
|
inner: T
|
||||||
req: HttpRequest<S>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Deref for Path<T, S> {
|
impl<T> Deref for Path<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
&self.item
|
&self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> DerefMut for Path<T, S> {
|
impl<T> DerefMut for Path<T> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
&mut self.item
|
&mut self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Path<T, S> {
|
impl<T> Path<T> {
|
||||||
|
/// Deconstruct to a inner value
|
||||||
/// Shared application state
|
pub fn into_inner(self) -> T {
|
||||||
#[inline]
|
self.inner
|
||||||
pub fn state(&self) -> &S {
|
|
||||||
self.req.state()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Incoming request
|
|
||||||
#[inline]
|
|
||||||
pub fn request(&self) -> &HttpRequest<S> {
|
|
||||||
&self.req
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deconstruct instance into parts
|
|
||||||
pub fn into(self) -> (T, HttpRequest<S>) {
|
|
||||||
(self.item, self.req)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> FromRequest<S> for Path<T, S>
|
impl<T, S> FromRequest<S> for Path<T>
|
||||||
where T: DeserializeOwned, S: 'static
|
where T: DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
@ -118,14 +98,12 @@ impl<T, S> FromRequest<S> for Path<T, S>
|
|||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
result(de::Deserialize::deserialize(PathDeserializer{req: &req})
|
result(de::Deserialize::deserialize(PathDeserializer{req: &req})
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
.map(|item| Path{item, req}))
|
.map(|inner| Path{inner}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract typed information from from the request's query.
|
/// Extract typed information from from the request's query.
|
||||||
///
|
///
|
||||||
/// `S` - application state type
|
|
||||||
///
|
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -136,9 +114,6 @@ impl<T, S> FromRequest<S> for Path<T, S>
|
|||||||
/// # use actix_web::*;
|
/// # use actix_web::*;
|
||||||
/// use actix_web::Query;
|
/// use actix_web::Query;
|
||||||
///
|
///
|
||||||
/// /// Application state
|
|
||||||
/// struct State {}
|
|
||||||
///
|
|
||||||
/// #[derive(Deserialize)]
|
/// #[derive(Deserialize)]
|
||||||
/// struct Info {
|
/// struct Info {
|
||||||
/// username: String,
|
/// username: String,
|
||||||
@ -146,56 +121,40 @@ impl<T, S> FromRequest<S> for Path<T, S>
|
|||||||
///
|
///
|
||||||
/// // use `with` extractor for query info
|
/// // use `with` extractor for query info
|
||||||
/// // this handler get called only if request's query contains `username` field
|
/// // this handler get called only if request's query contains `username` field
|
||||||
/// fn index(info: Query<Info, State>) -> Result<String> {
|
/// fn index(info: Query<Info>) -> Result<String> {
|
||||||
/// Ok(format!("Welcome {}!", info.username))
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::with_state(State{}).resource(
|
/// let app = Application::new().resource(
|
||||||
/// "/index.html",
|
/// "/index.html",
|
||||||
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Query<T, S=()>{
|
pub struct Query<T>(T);
|
||||||
item: T,
|
|
||||||
req: HttpRequest<S>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, S> Deref for Query<T, S> {
|
impl<T> Deref for Query<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
&self.item
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> DerefMut for Query<T, S> {
|
impl<T> DerefMut for Query<T> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
&mut self.item
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Query<T, S> {
|
impl<T> Query<T> {
|
||||||
|
/// Deconstruct to a inner value
|
||||||
/// Shared application state
|
pub fn into_inner(self) -> T {
|
||||||
#[inline]
|
self.0
|
||||||
pub fn state(&self) -> &S {
|
|
||||||
self.req.state()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Incoming request
|
|
||||||
#[inline]
|
|
||||||
pub fn request(&self) -> &HttpRequest<S> {
|
|
||||||
&self.req
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deconstruct instance into parts
|
|
||||||
pub fn into(self) -> (T, HttpRequest<S>) {
|
|
||||||
(self.item, self.req)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> FromRequest<S> for Query<T, S>
|
impl<T, S> FromRequest<S> for Query<T>
|
||||||
where T: de::DeserializeOwned, S: 'static
|
where T: de::DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
@ -205,7 +164,7 @@ impl<T, S> FromRequest<S> for Query<T, S>
|
|||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
result(serde_urlencoded::from_str::<T>(req.query_string())
|
result(serde_urlencoded::from_str::<T>(req.query_string())
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
.map(|item| Query{ item, req}))
|
.map(Query))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,7 +540,7 @@ mod tests {
|
|||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<MyStruct, _>::from_request(&req).poll().unwrap() {
|
match Path::<MyStruct>::from_request(&req).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.key, "name");
|
assert_eq!(s.key, "name");
|
||||||
assert_eq!(s.value, "user1");
|
assert_eq!(s.value, "user1");
|
||||||
@ -589,7 +548,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, String), _>::from_request(&req).poll().unwrap() {
|
match Path::<(String, String)>::from_request(&req).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, "user1");
|
assert_eq!(s.1, "user1");
|
||||||
@ -597,7 +556,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Query::<Id, _>::from_request(&req).poll().unwrap() {
|
match Query::<Id>::from_request(&req).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.id, "test");
|
assert_eq!(s.id, "test");
|
||||||
},
|
},
|
||||||
@ -607,7 +566,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::with_uri("/name/32/").finish();
|
let mut req = TestRequest::with_uri("/name/32/").finish();
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<Test2, _>::from_request(&req).poll().unwrap() {
|
match Path::<Test2>::from_request(&req).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.key, "name");
|
assert_eq!(s.key, "name");
|
||||||
assert_eq!(s.value, 32);
|
assert_eq!(s.value, 32);
|
||||||
@ -615,7 +574,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, u8), _>::from_request(&req).poll().unwrap() {
|
match Path::<(String, u8)>::from_request(&req).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, 32);
|
assert_eq!(s.1, 32);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use futures::future::{Future, ok, err};
|
use futures::future::{Future, FutureResult, ok, err};
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
@ -347,3 +348,57 @@ impl<S, H, F, R, E> RouteHandler<S> for AsyncHandler<S, H, F, R, E>
|
|||||||
Reply::async(fut)
|
Reply::async(fut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Access to an application state
|
||||||
|
///
|
||||||
|
/// `S` - application state type
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate bytes;
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// # extern crate futures;
|
||||||
|
/// # use actix_web::*;
|
||||||
|
/// #[macro_use] extern crate serde_derive;
|
||||||
|
/// use actix_web::State;
|
||||||
|
///
|
||||||
|
/// /// Application state
|
||||||
|
/// struct App {msg: &'static str}
|
||||||
|
///
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// struct Info {
|
||||||
|
/// username: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// /// extract path info using serde
|
||||||
|
/// fn index(state: State<App>, info: Path<Info>) -> Result<String> {
|
||||||
|
/// Ok(format!("{} {}!", state.msg, info.username))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = Application::with_state(App{msg: "Welcome"}).resource(
|
||||||
|
/// "/{username}/index.html", // <- define path parameters
|
||||||
|
/// |r| r.method(Method::GET).with2(index)); // <- use `with` extractor
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct State<S> (HttpRequest<S>);
|
||||||
|
|
||||||
|
impl<S> Deref for State<S> {
|
||||||
|
type Target = S;
|
||||||
|
|
||||||
|
fn deref(&self) -> &S {
|
||||||
|
self.0.state()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static> FromRequest<S> for State<S>
|
||||||
|
{
|
||||||
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
||||||
|
ok(State(req.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -141,7 +141,7 @@ pub use application::Application;
|
|||||||
pub use httpmessage::HttpMessage;
|
pub use httpmessage::HttpMessage;
|
||||||
pub use httprequest::HttpRequest;
|
pub use httprequest::HttpRequest;
|
||||||
pub use httpresponse::HttpResponse;
|
pub use httpresponse::HttpResponse;
|
||||||
pub use handler::{Either, Responder, AsyncResponder, FutureResponse};
|
pub use handler::{Either, Responder, AsyncResponder, FutureResponse, State};
|
||||||
pub use context::HttpContext;
|
pub use context::HttpContext;
|
||||||
pub use server::HttpServer;
|
pub use server::HttpServer;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user