mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
refactor WithHandler trait
This commit is contained in:
parent
62fb75ff95
commit
4358da9926
@ -31,7 +31,7 @@ fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This handler uses `With` helper for loading serde json object.
|
/// This handler uses `With` helper for loading serde json object.
|
||||||
fn extract_item(_: HttpRequest, item: Json<MyObj>) -> Result<HttpResponse> {
|
fn extract_item(item: Json<MyObj>) -> Result<HttpResponse> {
|
||||||
println!("model: {:?}", &item);
|
println!("model: {:?}", &item);
|
||||||
httpcodes::HTTPOk.build().json(item.0) // <- send response
|
httpcodes::HTTPOk.build().json(item.0) // <- send response
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ use error::Error;
|
|||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
|
||||||
|
|
||||||
pub trait HttpRequestExtractor<T>: Sized where T: DeserializeOwned
|
pub trait HttpRequestExtractor<T, S>: Sized where T: DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
type Result: Future<Item=Self, Error=Error>;
|
type Result: Future<Item=Self, Error=Error>;
|
||||||
|
|
||||||
fn extract<S: 'static>(req: &HttpRequest<S>) -> Self::Result;
|
fn extract(req: &HttpRequest<S>) -> Self::Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract typed information from the request's path.
|
/// Extract typed information from the request's path.
|
||||||
@ -33,7 +33,7 @@ pub trait HttpRequestExtractor<T>: Sized where T: DeserializeOwned
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /// extract path info using serde
|
/// /// extract path info using serde
|
||||||
/// fn index(req: HttpRequest, info: Path<Info>) -> Result<String> {
|
/// fn index(info: Path<Info>) -> Result<String> {
|
||||||
/// Ok(format!("Welcome {}!", info.username))
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -43,31 +43,57 @@ pub trait HttpRequestExtractor<T>: Sized where T: DeserializeOwned
|
|||||||
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Path<T>(pub T);
|
pub struct Path<T, S=()>{
|
||||||
|
item: T,
|
||||||
|
req: HttpRequest<S>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for Path<T> {
|
impl<T, S> Deref for Path<T, S> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
&self.0
|
&self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for Path<T> {
|
impl<T, S> DerefMut for Path<T, S> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
&mut self.0
|
&mut self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HttpRequestExtractor<T> for Path<T> where T: DeserializeOwned
|
impl<T, S> Path<T, S> {
|
||||||
|
|
||||||
|
/// Shared application state
|
||||||
|
#[inline]
|
||||||
|
pub fn state(&self) -> &S {
|
||||||
|
self.req.state()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Incoming request
|
||||||
|
#[inline]
|
||||||
|
pub fn request(&self) -> &HttpRequest<S> {
|
||||||
|
&self.req
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deconstruct instance into a parts
|
||||||
|
pub fn into(self) -> (T, HttpRequest<S>) {
|
||||||
|
(self.item, self.req)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S> HttpRequestExtractor<T, S> for Path<T, S>
|
||||||
|
where T: DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extract<S: 'static>(req: &HttpRequest<S>) -> Self::Result {
|
fn extract(req: &HttpRequest<S>) -> Self::Result {
|
||||||
result(de::Deserialize::deserialize(PathExtractor{req})
|
let req = req.clone();
|
||||||
|
result(de::Deserialize::deserialize(PathExtractor{req: &req})
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
.map(Path))
|
.map(|item| Path{item, req}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +116,7 @@ impl<T> HttpRequestExtractor<T> for Path<T> where T: DeserializeOwned
|
|||||||
///
|
///
|
||||||
/// // 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(req: HttpRequest, info: Query<Info>) -> Result<String> {
|
/// fn index(info: Query<Info>) -> Result<String> {
|
||||||
/// Ok(format!("Welcome {}!", info.username))
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -100,31 +126,56 @@ impl<T> HttpRequestExtractor<T> for Path<T> where T: DeserializeOwned
|
|||||||
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
/// |r| r.method(Method::GET).with(index)); // <- use `with` extractor
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Query<T>(pub T);
|
pub struct Query<T, S=()>{
|
||||||
|
item: T,
|
||||||
|
req: HttpRequest<S>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for Query<T> {
|
impl<T, S> Deref for Query<T, S> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
&self.0
|
&self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DerefMut for Query<T> {
|
impl<T, S> DerefMut for Query<T, S> {
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
&mut self.0
|
&mut self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HttpRequestExtractor<T> for Query<T> where T: de::DeserializeOwned
|
impl<T, S> Query<T, S> {
|
||||||
|
|
||||||
|
/// Shared application state
|
||||||
|
#[inline]
|
||||||
|
pub fn state(&self) -> &S {
|
||||||
|
self.req.state()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Incoming request
|
||||||
|
#[inline]
|
||||||
|
pub fn request(&self) -> &HttpRequest<S> {
|
||||||
|
&self.req
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deconstruct instance into a parts
|
||||||
|
pub fn into(self) -> (T, HttpRequest<S>) {
|
||||||
|
(self.item, self.req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S> HttpRequestExtractor<T, S> for Query<T, S>
|
||||||
|
where T: de::DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extract<S: 'static>(req: &HttpRequest<S>) -> Self::Result {
|
fn extract(req: &HttpRequest<S>) -> Self::Result {
|
||||||
|
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(Query))
|
.map(|item| Query{ item, req}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ pub trait HttpMessage {
|
|||||||
MessageBody::new(self)
|
MessageBody::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `application/x-www-form-urlencoded` encoded body.
|
/// Parse `application/x-www-form-urlencoded` encoded request's body.
|
||||||
/// Return `UrlEncoded` future. It resolves to a `HashMap<String, String>` which
|
/// Return `UrlEncoded` future. It resolves to a `HashMap<String, String>` which
|
||||||
/// contains decoded parameters.
|
/// contains decoded parameters.
|
||||||
///
|
///
|
||||||
@ -151,15 +151,15 @@ pub trait HttpMessage {
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// # extern crate futures;
|
/// # extern crate futures;
|
||||||
|
/// # use futures::Future;
|
||||||
/// use actix_web::*;
|
/// use actix_web::*;
|
||||||
/// use futures::future::{Future, ok};
|
|
||||||
///
|
///
|
||||||
/// fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
/// fn index(mut req: HttpRequest) -> FutureResponse<HttpResponse> {
|
||||||
/// req.urlencoded() // <- get UrlEncoded future
|
/// req.urlencoded() // <- get UrlEncoded future
|
||||||
/// .from_err()
|
/// .from_err()
|
||||||
/// .and_then(|params| { // <- url encoded parameters
|
/// .and_then(|params| { // <- url encoded parameters
|
||||||
/// println!("==== BODY ==== {:?}", params);
|
/// println!("==== BODY ==== {:?}", params);
|
||||||
/// ok(httpcodes::HttpOk.into())
|
/// Ok(httpcodes::HttpOk.into())
|
||||||
/// })
|
/// })
|
||||||
/// .responder()
|
/// .responder()
|
||||||
/// }
|
/// }
|
||||||
|
@ -430,8 +430,8 @@ impl<S> HttpRequest<S> {
|
|||||||
where S: 'static,
|
where S: 'static,
|
||||||
T: de::DeserializeOwned,
|
T: de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
match Path::<T>::extract(self).poll()? {
|
match Path::<T, _>::extract(self).poll()? {
|
||||||
Async::Ready(val) => Ok(val.0),
|
Async::Ready(val) => Ok(val.into().0),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,8 +482,8 @@ impl<S> HttpRequest<S> {
|
|||||||
where S: 'static,
|
where S: 'static,
|
||||||
T: de::DeserializeOwned,
|
T: de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
match Query::<T>::extract(self).poll()? {
|
match Query::<T, _>::extract(self).poll()? {
|
||||||
Async::Ready(val) => Ok(val.0),
|
Async::Ready(val) => Ok(val.into().0),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,12 +63,13 @@ impl<T: Serialize> Responder for Json<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HttpRequestExtractor<T> for Json<T> where T: DeserializeOwned + 'static
|
impl<T, S> HttpRequestExtractor<T, S> for Json<T>
|
||||||
|
where T: DeserializeOwned + 'static, S: 'static
|
||||||
{
|
{
|
||||||
type Result = Box<Future<Item=Self, Error=Error>>;
|
type Result = Box<Future<Item=Self, Error=Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extract<S: 'static>(req: &HttpRequest<S>) -> Self::Result {
|
fn extract(req: &HttpRequest<S>) -> Self::Result {
|
||||||
Box::new(
|
Box::new(
|
||||||
JsonBody::new(req.clone())
|
JsonBody::new(req.clone())
|
||||||
.from_err()
|
.from_err()
|
||||||
@ -251,7 +252,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_json() {
|
fn test_with_json() {
|
||||||
let mut handler = with(|_: _, data: Json<MyObject>| data);
|
let mut handler = with(|data: Json<MyObject>| data);
|
||||||
|
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let mut json = handler.handle(req).into_future();
|
let mut json = handler.handle(req).into_future();
|
||||||
|
@ -144,7 +144,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn with<T, D, H>(&mut self, handler: H)
|
pub fn with<T, D, H>(&mut self, handler: H)
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T> + 'static,
|
D: HttpRequestExtractor<T, S> + 'static,
|
||||||
T: DeserializeOwned + 'static,
|
T: DeserializeOwned + 'static,
|
||||||
{
|
{
|
||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
|
@ -127,7 +127,7 @@ impl<S: 'static> Route<S> {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /// extract path info using serde
|
/// /// extract path info using serde
|
||||||
/// fn index(req: HttpRequest, info: Path<Info>) -> Result<String> {
|
/// fn index(info: Path<Info>) -> Result<String> {
|
||||||
/// Ok(format!("Welcome {}!", info.username))
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -139,7 +139,7 @@ impl<S: 'static> Route<S> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn with<T, D, H>(&mut self, handler: H)
|
pub fn with<T, D, H>(&mut self, handler: H)
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T> + 'static,
|
D: HttpRequestExtractor<T, S> + 'static,
|
||||||
T: DeserializeOwned + 'static,
|
T: DeserializeOwned + 'static,
|
||||||
{
|
{
|
||||||
self.h(with(handler))
|
self.h(with(handler))
|
||||||
|
28
src/with.rs
28
src/with.rs
@ -14,32 +14,33 @@ use extractor::HttpRequestExtractor;
|
|||||||
/// Trait defines object that could be registered as route handler
|
/// Trait defines object that could be registered as route handler
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait WithHandler<T, D, S>: 'static
|
pub trait WithHandler<T, D, S>: 'static
|
||||||
where D: HttpRequestExtractor<T>, T: DeserializeOwned
|
where D: HttpRequestExtractor<T, S>, T: DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
/// The type of value that handler will return.
|
/// The type of value that handler will return.
|
||||||
type Result: Responder;
|
type Result: Responder;
|
||||||
|
|
||||||
/// Handle request
|
/// Handle request
|
||||||
fn handle(&mut self, req: HttpRequest<S>, data: D) -> Self::Result;
|
fn handle(&mut self, data: D) -> Self::Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WithHandler<D, T, S> for Fn()
|
/// WithHandler<D, T, S> for Fn()
|
||||||
impl<T, D, S, F, R> WithHandler<T, D, S> for F
|
impl<T, D, S, F, R> WithHandler<T, D, S> for F
|
||||||
where F: Fn(HttpRequest<S>, D) -> R + 'static,
|
where F: Fn(D) -> R + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
|
S: 'static,
|
||||||
{
|
{
|
||||||
type Result = R;
|
type Result = R;
|
||||||
|
|
||||||
fn handle(&mut self, req: HttpRequest<S>, item: D) -> R {
|
fn handle(&mut self, item: D) -> R {
|
||||||
(self)(req, item)
|
(self)(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with<T, D, S, H>(h: H) -> With<T, D, S, H>
|
pub(crate) fn with<T, D, S, H>(h: H) -> With<T, D, S, H>
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
{
|
{
|
||||||
With{hnd: Rc::new(UnsafeCell::new(h)),
|
With{hnd: Rc::new(UnsafeCell::new(h)),
|
||||||
@ -48,8 +49,9 @@ pub(crate) fn with<T, D, S, H>(h: H) -> With<T, D, S, H>
|
|||||||
|
|
||||||
pub struct With<T, D, S, H>
|
pub struct With<T, D, S, H>
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
|
S: 'static,
|
||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<H>>,
|
hnd: Rc<UnsafeCell<H>>,
|
||||||
_t: PhantomData<T>,
|
_t: PhantomData<T>,
|
||||||
@ -59,9 +61,9 @@ pub struct With<T, D, S, H>
|
|||||||
|
|
||||||
impl<T, D, S, H> Handler<S> for With<T, D, S, H>
|
impl<T, D, S, H> Handler<S> for With<T, D, S, H>
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
T: 'static, D: 'static, S: 'static
|
T: 'static, D: 'static, S: 'static, H: 'static
|
||||||
{
|
{
|
||||||
type Result = Reply;
|
type Result = Reply;
|
||||||
|
|
||||||
@ -82,7 +84,7 @@ impl<T, D, S, H> Handler<S> for With<T, D, S, H>
|
|||||||
|
|
||||||
struct WithHandlerFut<T, D, S, H>
|
struct WithHandlerFut<T, D, S, H>
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
T: 'static, D: 'static, S: 'static
|
T: 'static, D: 'static, S: 'static
|
||||||
{
|
{
|
||||||
@ -96,7 +98,7 @@ struct WithHandlerFut<T, D, S, H>
|
|||||||
|
|
||||||
impl<T, D, S, H> Future for WithHandlerFut<T, D, S, H>
|
impl<T, D, S, H> Future for WithHandlerFut<T, D, S, H>
|
||||||
where H: WithHandler<T, D, S>,
|
where H: WithHandler<T, D, S>,
|
||||||
D: HttpRequestExtractor<T>,
|
D: HttpRequestExtractor<T, S>,
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
T: 'static, D: 'static, S: 'static
|
T: 'static, D: 'static, S: 'static
|
||||||
{
|
{
|
||||||
@ -114,7 +116,7 @@ impl<T, D, S, H> Future for WithHandlerFut<T, D, S, H>
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hnd: &mut H = unsafe{&mut *self.hnd.get()};
|
let hnd: &mut H = unsafe{&mut *self.hnd.get()};
|
||||||
let item = match hnd.handle(self.req.clone(), item)
|
let item = match hnd.handle(item)
|
||||||
.respond_to(self.req.without_state())
|
.respond_to(self.req.without_state())
|
||||||
{
|
{
|
||||||
Ok(item) => item.into(),
|
Ok(item) => item.into(),
|
||||||
|
Loading…
Reference in New Issue
Block a user