1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-30 18:34:36 +01:00

Added initial support for PathConfig, allows setting custom error handler. (#903)

This commit is contained in:
Lucas Berezy 2019-06-12 20:49:56 +10:00 committed by Nikolay Kim
parent 36e6f0cb4b
commit 13e618b128
3 changed files with 98 additions and 3 deletions

View File

@ -92,6 +92,25 @@ impl ResponseError for JsonPayloadError {
} }
} }
/// A set of errors that can occur during parsing request paths
#[derive(Debug, Display, From)]
pub enum PathPayloadError {
/// Deserialize error
#[display(fmt = "Path deserialize error: {}", _0)]
Deserialize(de::Error),
}
/// Return `BadRequest` for `PathPayloadError`
impl ResponseError for PathPayloadError {
fn error_response(&self) -> HttpResponse {
match *self {
PathPayloadError::Deserialize(_) => {
HttpResponse::new(StatusCode::BAD_REQUEST)
}
}
}
}
/// A set of errors that can occur during parsing query strings /// A set of errors that can occur during parsing query strings
#[derive(Debug, Display, From)] #[derive(Debug, Display, From)]
pub enum QueryPayloadError { pub enum QueryPayloadError {

View File

@ -9,6 +9,6 @@ pub(crate) mod readlines;
pub use self::form::{Form, FormConfig}; pub use self::form::{Form, FormConfig};
pub use self::json::{Json, JsonConfig}; pub use self::json::{Json, JsonConfig};
pub use self::path::Path; pub use self::path::{Path, PathConfig};
pub use self::payload::{Payload, PayloadConfig}; pub use self::payload::{Payload, PayloadConfig};
pub use self::query::{Query, QueryConfig}; pub use self::query::{Query, QueryConfig};

View File

@ -1,5 +1,6 @@
//! Path extractor //! Path extractor
use std::sync::Arc;
use std::{fmt, ops}; use std::{fmt, ops};
use actix_http::error::{Error, ErrorNotFound}; use actix_http::error::{Error, ErrorNotFound};
@ -7,6 +8,7 @@ use actix_router::PathDeserializer;
use serde::de; use serde::de;
use crate::dev::Payload; use crate::dev::Payload;
use crate::error::PathPayloadError;
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::FromRequest; use crate::FromRequest;
@ -156,15 +158,89 @@ impl<T> FromRequest for Path<T>
where where
T: de::DeserializeOwned, T: de::DeserializeOwned,
{ {
type Config = ();
type Error = Error; type Error = Error;
type Future = Result<Self, Error>; type Future = Result<Self, Error>;
type Config = PathConfig;
#[inline] #[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
let error_handler = req
.app_data::<Self::Config>()
.map(|c| c.ehandler.clone())
.unwrap_or(None);
de::Deserialize::deserialize(PathDeserializer::new(req.match_info())) de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
.map(|inner| Path { inner }) .map(|inner| Path { inner })
.map_err(ErrorNotFound) .map_err(move |e| {
log::debug!(
"Failed during Path extractor deserialization. \
Request path: {:?}",
req.path()
);
if let Some(error_handler) = error_handler {
let e = PathPayloadError::Deserialize(e);
(error_handler)(e, req)
} else {
ErrorNotFound(e)
}
})
}
}
/// Path extractor configuration
///
/// ```rust
// #[macro_use]
// extern crate serde_derive;
// use actix_web::web::PathConfig;
// use actix_web::{error, web, App, FromRequest, HttpResponse};
// #[derive(Deserialize, Debug)]
// enum Folder {
// #[serde(rename = "inbox")]
// Inbox,
// #[serde(rename = "outbox")]
// Outbox,
// }
// /// deserialize `Info` from request's path
// fn index(folder: web::Path<Folder>) -> String {
// format!("Selected folder: {}!", folder)
// }
// fn main() {
// let app = App::new().service(
// web::resource("messages/{folder}")
// .data(PathConfig::default().error_handler(|err, req| {
// error::InternalError::from_response(
// err,
// HttpResponse::Conflict().finish(),
// )
// .into()
// }))
// .route(web::post().to(index)),
// );
// }
/// ```
#[derive(Clone)]
pub struct PathConfig {
ehandler: Option<Arc<Fn(PathPayloadError, &HttpRequest) -> Error + Send + Sync>>,
}
impl PathConfig {
/// Set custom error handler
pub fn error_handler<F>(mut self, f: F) -> Self
where
F: Fn(PathPayloadError, &HttpRequest) -> Error + Send + Sync + 'static,
{
self.ehandler = Some(Arc::new(f));
self
}
}
impl Default for PathConfig {
fn default() -> Self {
PathConfig { ehandler: None }
} }
} }