mirror of https://github.com/fafhrd91/actix-web
FromRequestX
This commit is contained in:
parent
66620a1012
commit
2f8fbf8d3b
30
src/data.rs
30
src/data.rs
|
@ -6,8 +6,8 @@ use futures_core::future::LocalBoxFuture;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dev::Payload, error::ErrorInternalServerError, extract::FromRequest, request::HttpRequest,
|
dev::Payload, error::ErrorInternalServerError, request::HttpRequest, Error, FromRequest,
|
||||||
Error,
|
FromRequestX,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Data factory.
|
/// Data factory.
|
||||||
|
@ -143,6 +143,29 @@ impl<T: ?Sized + 'static> FromRequest for Data<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized + 'static> FromRequestX<'a> for &Data<T> {
|
||||||
|
type Output = &'a Data<T>;
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Ready<Result<Self::Output, Error>>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_request(req: &'a HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
|
if let Some(st) = req.app_data::<Data<T>>() {
|
||||||
|
ok(st)
|
||||||
|
} else {
|
||||||
|
log::debug!(
|
||||||
|
"Failed to construct App-level Data extractor. \
|
||||||
|
Request path: {:?} (type: {})",
|
||||||
|
req.path(),
|
||||||
|
type_name::<T>(),
|
||||||
|
);
|
||||||
|
err(ErrorInternalServerError(
|
||||||
|
"App data is not configured, to configure construct it with web::Data::new() and pass it to App::app_data()",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + 'static> DataFactory for Data<T> {
|
impl<T: ?Sized + 'static> DataFactory for Data<T> {
|
||||||
fn create(&self, extensions: &mut Extensions) -> bool {
|
fn create(&self, extensions: &mut Extensions) -> bool {
|
||||||
extensions.insert(Data(self.0.clone()));
|
extensions.insert(Data(self.0.clone()));
|
||||||
|
@ -160,6 +183,9 @@ mod tests {
|
||||||
web, App, HttpResponse,
|
web, App, HttpResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
trait FromRequest {}
|
||||||
|
|
||||||
// allow deprecated App::data
|
// allow deprecated App::data
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
|
|
@ -76,6 +76,38 @@ pub trait FromRequest: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FromRequestX<'a>: Sized {
|
||||||
|
/// Must be Self unless the extractor borrows request.
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
/// The associated error which can be returned.
|
||||||
|
// TODO Consider adding 'static bound
|
||||||
|
type Error: Into<Error>;
|
||||||
|
|
||||||
|
/// Future that resolves to a Self.
|
||||||
|
type Future: Future<Output = Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
|
/// Create a Self from request parts asynchronously.
|
||||||
|
fn from_request(req: &'a HttpRequest, payload: &mut Payload) -> Self::Future;
|
||||||
|
|
||||||
|
/// Create a Self from request head asynchronously.
|
||||||
|
///
|
||||||
|
/// This method is short for `T::from_request(req, &mut Payload::None)`.
|
||||||
|
fn extract(req: &'a HttpRequest) -> Self::Future {
|
||||||
|
Self::from_request(req, &mut Payload::None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: FromRequest> FromRequestX<'a> for T {
|
||||||
|
type Output = Self;
|
||||||
|
type Error = <Self as FromRequest>::Error;
|
||||||
|
type Future = <Self as FromRequest>::Future;
|
||||||
|
|
||||||
|
fn from_request(req: &'a HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
|
Self::from_request(req, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Optionally extract a field from the request
|
/// Optionally extract a field from the request
|
||||||
///
|
///
|
||||||
/// If the FromRequest for T fails, return None rather than returning an error response
|
/// If the FromRequest for T fails, return None rather than returning an error response
|
||||||
|
@ -123,16 +155,16 @@ pub trait FromRequest: Sized {
|
||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
impl<T: 'static> FromRequest for Option<T>
|
impl<'a, T> FromRequestX<'a> for Option<T>
|
||||||
where
|
where
|
||||||
T: FromRequest,
|
T: FromRequestX<'a>,
|
||||||
T::Future: 'static,
|
|
||||||
{
|
{
|
||||||
|
type Output = Option<T::Output>;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = FromRequestOptFuture<T::Future>;
|
type Future = FromRequestOptFuture<T::Future>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &'a HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
FromRequestOptFuture {
|
FromRequestOptFuture {
|
||||||
fut: T::from_request(req, payload),
|
fut: T::from_request(req, payload),
|
||||||
}
|
}
|
||||||
|
@ -209,6 +241,7 @@ where
|
||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
// TODO
|
||||||
impl<T> FromRequest for Result<T, T::Error>
|
impl<T> FromRequest for Result<T, T::Error>
|
||||||
where
|
where
|
||||||
T: FromRequest + 'static,
|
T: FromRequest + 'static,
|
||||||
|
@ -266,6 +299,26 @@ impl FromRequest for Uri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> FromRequestX<'a> for &Uri {
|
||||||
|
type Output = &'a Uri;
|
||||||
|
type Error = Infallible;
|
||||||
|
type Future = Ready<Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &'a HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
|
ok(req.uri())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FromRequestX<'a> for &HttpRequest {
|
||||||
|
type Output = &'a HttpRequest;
|
||||||
|
type Error = Infallible;
|
||||||
|
type Future = Ready<Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
|
fn from_request(req: &'a HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
|
ok(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extract the request's method.
|
/// Extract the request's method.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -318,38 +371,41 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
|
||||||
// redundant imports
|
// redundant imports
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A helper struct to allow us to pin-project through
|
/// A helper struct to allow us to pin-project through
|
||||||
/// to individual fields
|
/// to individual fields
|
||||||
#[pin_project::pin_project]
|
#[pin_project::pin_project]
|
||||||
struct FutWrapper<$($T: FromRequest),+>($(#[pin] $T::Future),+);
|
struct FutWrapper<'a, $($T: FromRequestX<'a>),+>($(#[pin] $T::Future,)+ PhantomData<&'a ()>);
|
||||||
|
|
||||||
/// FromRequest implementation for tuple
|
/// FromRequest implementation for tuple
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
|
impl<'a, $($T: FromRequestX<'a>),+> FromRequestX<'a> for ($($T,)+)
|
||||||
{
|
{
|
||||||
|
type Output = ($($T::Output,)+);
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = $fut_type<$($T),+>;
|
type Future = $fut_type<'a, $($T),+>;
|
||||||
|
|
||||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &'a HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
$fut_type {
|
$fut_type {
|
||||||
items: <($(Option<$T>,)+)>::default(),
|
items: <($(Option<$T::Output>,)+)>::default(),
|
||||||
futs: FutWrapper($($T::from_request(req, payload),)+),
|
futs: FutWrapper($($T::from_request(req, payload),)+ PhantomData),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[pin_project::pin_project]
|
#[pin_project::pin_project]
|
||||||
pub struct $fut_type<$($T: FromRequest),+> {
|
pub struct $fut_type<'a, $($T: FromRequestX<'a>),+> {
|
||||||
items: ($(Option<$T>,)+),
|
items: ($(Option<$T::Output>,)+),
|
||||||
#[pin]
|
#[pin]
|
||||||
futs: FutWrapper<$($T,)+>,
|
futs: FutWrapper<'a, $($T,)+>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<$($T: FromRequest),+> Future for $fut_type<$($T),+>
|
impl<'a, $($T: FromRequestX<'a>),+> Future for $fut_type<'a, $($T),+>
|
||||||
{
|
{
|
||||||
type Output = Result<($($T,)+), Error>;
|
type Output = Result<($($T::Output,)+), Error>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let mut this = self.project();
|
let mut this = self.project();
|
||||||
|
@ -405,6 +461,9 @@ mod tests {
|
||||||
use crate::test::TestRequest;
|
use crate::test::TestRequest;
|
||||||
use crate::types::{Form, FormConfig};
|
use crate::types::{Form, FormConfig};
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
trait FromRequest {}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
struct Info {
|
struct Info {
|
||||||
hello: String,
|
hello: String,
|
||||||
|
|
140
src/handler.rs
140
src/handler.rs
|
@ -7,31 +7,47 @@ use actix_service::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
Error, FromRequest, HttpResponse, Responder,
|
Error, FromRequestX, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO inaccessible docs
|
||||||
/// A request handler is an async function that accepts zero or more parameters that can be
|
/// A request handler is an async function that accepts zero or more parameters that can be
|
||||||
/// extracted from a request (i.e., [`impl FromRequest`](crate::FromRequest)) and returns a type
|
/// extracted from a request (i.e., [`impl FromRequest`](crate::FromRequest)) and returns a type
|
||||||
/// that can be converted into an [`HttpResponse`] (that is, it impls the [`Responder`] trait).
|
/// that can be converted into an [`HttpResponse`] (that is, it impls the [`Responder`] trait).
|
||||||
///
|
///
|
||||||
/// If you got the error `the trait Handler<_, _, _> is not implemented`, then your function is not
|
/// If you got the error `the trait Handler<_, _, _> is not implemented`, then your function is not
|
||||||
/// a valid handler. See [Request Handlers](https://actix.rs/docs/handlers/) for more information.
|
/// a valid handler. See [Request Handlers](https://actix.rs/docs/handlers/) for more information.
|
||||||
pub trait Handler<T, R>: Clone + 'static
|
pub trait Handler<'a, T: FromRequestX<'a>>: Clone + 'static {
|
||||||
where
|
// TODO why 'static ??
|
||||||
R: Future,
|
type Response: Responder + 'static;
|
||||||
R::Output: Responder,
|
type Future: Future<Output = Self::Response>;
|
||||||
{
|
|
||||||
fn call(&self, param: T) -> R;
|
fn handle(&'a self, _: T::Output) -> Self::Future;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handler_service<F, T, R>(
|
impl<'a, F, T, Fut, Resp> Handler<'a, T> for F
|
||||||
handler: F,
|
where
|
||||||
|
F: FnX<T>,
|
||||||
|
F: FnX<T::Output, Output = Fut>,
|
||||||
|
F: Clone + 'static,
|
||||||
|
T: FromRequestX<'a>,
|
||||||
|
Fut: Future<Output = Resp>,
|
||||||
|
Resp: Responder + 'static,
|
||||||
|
{
|
||||||
|
type Response = Resp;
|
||||||
|
type Future = Fut;
|
||||||
|
|
||||||
|
fn handle(&'a self, data: T::Output) -> Self::Future {
|
||||||
|
self.call(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handler_service<H, T>(
|
||||||
|
handler: H,
|
||||||
) -> BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>
|
) -> BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>
|
||||||
where
|
where
|
||||||
F: Handler<T, R>,
|
H: for<'a> Handler<'a, T>,
|
||||||
T: FromRequest,
|
T: for<'a> FromRequestX<'a>,
|
||||||
R: Future,
|
|
||||||
R::Output: Responder,
|
|
||||||
{
|
{
|
||||||
boxed::factory(fn_service(move |req: ServiceRequest| {
|
boxed::factory(fn_service(move |req: ServiceRequest| {
|
||||||
let handler = handler.clone();
|
let handler = handler.clone();
|
||||||
|
@ -39,37 +55,95 @@ where
|
||||||
let (req, mut payload) = req.into_parts();
|
let (req, mut payload) = req.into_parts();
|
||||||
let res = match T::from_request(&req, &mut payload).await {
|
let res = match T::from_request(&req, &mut payload).await {
|
||||||
Err(err) => HttpResponse::from_error(err),
|
Err(err) => HttpResponse::from_error(err),
|
||||||
Ok(data) => handler.call(data).await.respond_to(&req),
|
Ok(data) => handler.handle(data).await.respond_to(&req),
|
||||||
};
|
};
|
||||||
Ok(ServiceResponse::new(req, res))
|
Ok(ServiceResponse::new(req, res))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as [`std::ops::Fn`]
|
||||||
|
pub trait FnX<Args> {
|
||||||
|
type Output;
|
||||||
|
fn call(&self, args: Args) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
/// FromRequest trait impl for tuples
|
/// FromRequest trait impl for tuples
|
||||||
macro_rules! factory_tuple ({ $($param:ident)* } => {
|
macro_rules! fn_tuple ({ $($param:ident)* } => {
|
||||||
impl<Func, $($param,)* Res> Handler<($($param,)*), Res> for Func
|
impl<Func, $($param,)* O> FnX<($($param,)*)> for Func
|
||||||
where Func: Fn($($param),*) -> Res + Clone + 'static,
|
where Func: Fn($($param),*) -> O,
|
||||||
Res: Future,
|
|
||||||
Res::Output: Responder,
|
|
||||||
{
|
{
|
||||||
|
type Output = O;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn call(&self, ($($param,)*): ($($param,)*)) -> Res {
|
fn call(&self, ($($param,)*): ($($param,)*)) -> O {
|
||||||
(self)($($param,)*)
|
(self)($($param,)*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
factory_tuple! {}
|
fn_tuple! {}
|
||||||
factory_tuple! { A }
|
fn_tuple! { A }
|
||||||
factory_tuple! { A B }
|
fn_tuple! { A B }
|
||||||
factory_tuple! { A B C }
|
fn_tuple! { A B C }
|
||||||
factory_tuple! { A B C D }
|
fn_tuple! { A B C D }
|
||||||
factory_tuple! { A B C D E }
|
fn_tuple! { A B C D E }
|
||||||
factory_tuple! { A B C D E F }
|
fn_tuple! { A B C D E F }
|
||||||
factory_tuple! { A B C D E F G }
|
fn_tuple! { A B C D E F G }
|
||||||
factory_tuple! { A B C D E F G H }
|
fn_tuple! { A B C D E F G H }
|
||||||
factory_tuple! { A B C D E F G H I }
|
fn_tuple! { A B C D E F G H I }
|
||||||
factory_tuple! { A B C D E F G H I J }
|
fn_tuple! { A B C D E F G H I J }
|
||||||
factory_tuple! { A B C D E F G H I J K }
|
fn_tuple! { A B C D E F G H I J K }
|
||||||
factory_tuple! { A B C D E F G H I J K L }
|
fn_tuple! { A B C D E F G H I J K L }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
dev::Service,
|
||||||
|
http::StatusCode,
|
||||||
|
test::{init_service, TestRequest},
|
||||||
|
web, App, HttpRequest, HttpResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Params<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ParamsOwned {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handler(
|
||||||
|
req: &HttpRequest,
|
||||||
|
(data, params1): (Option<&web::Data<usize>>, web::Path<ParamsOwned>),
|
||||||
|
) -> HttpResponse {
|
||||||
|
let params2 = web::Path::<Params<'_>>::extract(req).await.unwrap();
|
||||||
|
assert_eq!(params1.name, "named");
|
||||||
|
assert_eq!(params2.name, "named");
|
||||||
|
|
||||||
|
assert_eq!(data.unwrap().as_ref(), &42);
|
||||||
|
|
||||||
|
HttpResponse::Ok().finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_borrowed_extractor() {
|
||||||
|
let srv = init_service(
|
||||||
|
App::new().service(
|
||||||
|
web::resource("/{name}")
|
||||||
|
.app_data(web::Data::new(42usize))
|
||||||
|
.route(web::get().to(handler)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/named").to_request();
|
||||||
|
let resp = srv.call(req).await.unwrap();
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub use cookie;
|
||||||
|
|
||||||
pub use crate::app::App;
|
pub use crate::app::App;
|
||||||
pub use crate::error::{Error, ResponseError, Result};
|
pub use crate::error::{Error, ResponseError, Result};
|
||||||
pub use crate::extract::FromRequest;
|
pub use crate::extract::{FromRequest, FromRequestX};
|
||||||
pub use crate::request::HttpRequest;
|
pub use crate::request::HttpRequest;
|
||||||
pub use crate::resource::Resource;
|
pub use crate::resource::Resource;
|
||||||
pub use crate::responder::Responder;
|
pub use crate::responder::Responder;
|
||||||
|
|
|
@ -16,12 +16,12 @@ use futures_util::future::join_all;
|
||||||
use crate::{
|
use crate::{
|
||||||
data::Data,
|
data::Data,
|
||||||
dev::{ensure_leading_slash, AppService, HttpServiceFactory, ResourceDef},
|
dev::{ensure_leading_slash, AppService, HttpServiceFactory, ResourceDef},
|
||||||
|
extract::FromRequestX,
|
||||||
guard::Guard,
|
guard::Guard,
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
responder::Responder,
|
|
||||||
route::{Route, RouteService},
|
route::{Route, RouteService},
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
Error, FromRequest, HttpResponse,
|
Error, HttpResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
type HttpService = BoxService<ServiceRequest, ServiceResponse, Error>;
|
type HttpService = BoxService<ServiceRequest, ServiceResponse, Error>;
|
||||||
|
@ -236,12 +236,10 @@ where
|
||||||
/// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
|
/// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
|
||||||
/// App::new().service(web::resource("/").route(web::route().to(index)));
|
/// App::new().service(web::resource("/").route(web::route().to(index)));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn to<F, I, R>(mut self, handler: F) -> Self
|
pub fn to<F, I>(mut self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Handler<I, R>,
|
F: for<'a> Handler<'a, I>,
|
||||||
I: FromRequest + 'static,
|
I: for<'a> FromRequestX<'a>,
|
||||||
R: Future + 'static,
|
|
||||||
R::Output: Responder + 'static,
|
|
||||||
{
|
{
|
||||||
self.routes.push(Route::new().to(handler));
|
self.routes.push(Route::new().to(handler));
|
||||||
self
|
self
|
||||||
|
|
13
src/route.rs
13
src/route.rs
|
@ -1,6 +1,6 @@
|
||||||
#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)
|
#![allow(clippy::rc_buffer)] // inner value is mutated before being shared (`Rc::get_mut`)
|
||||||
|
|
||||||
use std::{future::Future, rc::Rc};
|
use std::rc::Rc;
|
||||||
|
|
||||||
use actix_http::http::Method;
|
use actix_http::http::Method;
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
|
@ -10,10 +10,11 @@ use actix_service::{
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
extract::FromRequestX,
|
||||||
guard::{self, Guard},
|
guard::{self, Guard},
|
||||||
handler::{handler_service, Handler},
|
handler::{handler_service, Handler},
|
||||||
service::{ServiceRequest, ServiceResponse},
|
service::{ServiceRequest, ServiceResponse},
|
||||||
Error, FromRequest, HttpResponse, Responder,
|
Error, HttpResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resource route definition
|
/// Resource route definition
|
||||||
|
@ -175,12 +176,10 @@ impl Route {
|
||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn to<F, T, R>(mut self, handler: F) -> Self
|
pub fn to<F, T>(mut self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Handler<T, R>,
|
F: for<'a> Handler<'a, T>,
|
||||||
T: FromRequest + 'static,
|
T: for<'a> FromRequestX<'a>,
|
||||||
R: Future + 'static,
|
|
||||||
R::Output: Responder + 'static,
|
|
||||||
{
|
{
|
||||||
self.service = handler_service(handler);
|
self.service = handler_service(handler);
|
||||||
self
|
self
|
||||||
|
|
|
@ -9,7 +9,7 @@ use serde::de;
|
||||||
use crate::{
|
use crate::{
|
||||||
dev::Payload,
|
dev::Payload,
|
||||||
error::{Error, ErrorNotFound, PathError},
|
error::{Error, ErrorNotFound, PathError},
|
||||||
FromRequest, HttpRequest,
|
FromRequestX, HttpRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Extract typed data from request path segments.
|
/// Extract typed data from request path segments.
|
||||||
|
@ -91,15 +91,16 @@ impl<T: fmt::Display> fmt::Display for Path<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [here](#usage) for example of usage as an extractor.
|
/// See [here](#usage) for example of usage as an extractor.
|
||||||
impl<T> FromRequest for Path<T>
|
impl<'a, T> FromRequestX<'a> for Path<T>
|
||||||
where
|
where
|
||||||
T: de::DeserializeOwned,
|
T: de::Deserialize<'a>,
|
||||||
{
|
{
|
||||||
|
type Output = Self;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Ready<Result<Self, Self::Error>>;
|
type Future = Ready<Result<Self::Output, Self::Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
fn from_request(req: &'a HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
let error_handler = req
|
let error_handler = req
|
||||||
.app_data::<PathConfig>()
|
.app_data::<PathConfig>()
|
||||||
.and_then(|c| c.err_handler.clone());
|
.and_then(|c| c.err_handler.clone());
|
||||||
|
@ -266,6 +267,7 @@ mod tests {
|
||||||
resource.capture_match_info(req.match_info_mut());
|
resource.capture_match_info(req.match_info_mut());
|
||||||
|
|
||||||
let (req, mut pl) = req.into_parts();
|
let (req, mut pl) = req.into_parts();
|
||||||
|
|
||||||
let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
|
let s = Path::<Test2>::from_request(&req, &mut pl).await.unwrap();
|
||||||
assert_eq!(s.as_ref().key, "name");
|
assert_eq!(s.as_ref().key, "name");
|
||||||
assert_eq!(s.value, 32);
|
assert_eq!(s.value, 32);
|
||||||
|
|
12
src/web.rs
12
src/web.rs
|
@ -7,8 +7,8 @@ use actix_router::IntoPatterns;
|
||||||
pub use bytes::{Buf, BufMut, Bytes, BytesMut};
|
pub use bytes::{Buf, BufMut, Bytes, BytesMut};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::BlockingError, extract::FromRequest, handler::Handler, resource::Resource,
|
error::BlockingError, extract::FromRequestX, handler::Handler, resource::Resource,
|
||||||
responder::Responder, route::Route, scope::Scope, service::WebService,
|
route::Route, scope::Scope, service::WebService,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::config::ServiceConfig;
|
pub use crate::config::ServiceConfig;
|
||||||
|
@ -139,12 +139,10 @@ pub fn method(method: Method) -> Route {
|
||||||
/// web::to(index))
|
/// web::to(index))
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn to<F, I, R>(handler: F) -> Route
|
pub fn to<F, I>(handler: F) -> Route
|
||||||
where
|
where
|
||||||
F: Handler<I, R>,
|
F: for<'a> Handler<'a, I>,
|
||||||
I: FromRequest + 'static,
|
I: for<'a> FromRequestX<'a>,
|
||||||
R: Future + 'static,
|
|
||||||
R::Output: Responder + 'static,
|
|
||||||
{
|
{
|
||||||
Route::new().to(handler)
|
Route::new().to(handler)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue