add a way to configure error treatment for Query extractor

This commit is contained in:
François Mockers 2018-10-15 19:54:17 +02:00
parent 960274ada8
commit 1b20e288f2
1 changed files with 56 additions and 4 deletions

View File

@ -200,17 +200,69 @@ impl<T, S> FromRequest<S> for Query<T>
where where
T: de::DeserializeOwned, T: de::DeserializeOwned,
{ {
type Config = (); type Config = QueryConfig<S>;
type Result = Result<Self, Error>; type Result = Result<Self, Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
let req2 = req.clone();
let err = Rc::clone(&cfg.ehandler);
serde_urlencoded::from_str::<T>(req.query_string()) serde_urlencoded::from_str::<T>(req.query_string())
.map_err(|e| e.into()) .map_err(move |e| (*err)(e, &req2))
.map(Query) .map(Query)
} }
} }
/// Query extractor configuration
///
/// ```rust
/// # extern crate actix_web;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::{error, http, App, HttpResponse, Query, Result};
///
/// #[derive(Deserialize)]
/// struct Info {
/// username: String,
/// }
///
/// /// deserialize `Info` from request's body, max payload size is 4kb
/// fn index(info: Query<Info>) -> Result<String> {
/// Ok(format!("Welcome {}!", info.username))
/// }
///
/// fn main() {
/// let app = App::new().resource("/index.html", |r| {
/// r.method(http::Method::GET).with_config(index, |cfg| {
/// cfg.0.error_handler(|err, req| {
/// // <- create custom error response
/// error::InternalError::from_response(err, HttpResponse::Conflict().finish()).into()
/// });
/// })
/// });
/// }
/// ```
pub struct QueryConfig<S> {
ehandler: Rc<Fn(serde_urlencoded::de::Error, &HttpRequest<S>) -> Error>,
}
impl<S> QueryConfig<S> {
/// Set custom error handler
pub fn error_handler<F>(&mut self, f: F) -> &mut Self
where
F: Fn(serde_urlencoded::de::Error, &HttpRequest<S>) -> Error + 'static,
{
self.ehandler = Rc::new(f);
self
}
}
impl<S> Default for QueryConfig<S> {
fn default() -> Self {
QueryConfig {
ehandler: Rc::new(|e, _| e.into()),
}
}
}
impl<T: fmt::Debug> fmt::Debug for Query<T> { impl<T: fmt::Debug> fmt::Debug for Query<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f) self.0.fmt(f)
@ -959,7 +1011,7 @@ mod tests {
assert_eq!(s.0, "name"); assert_eq!(s.0, "name");
assert_eq!(s.1, "user1"); assert_eq!(s.1, "user1");
let s = Query::<Id>::from_request(&req, &()).unwrap(); let s = Query::<Id>::from_request(&req, &QueryConfig::default()).unwrap();
assert_eq!(s.id, "test"); assert_eq!(s.id, "test");
let mut router = Router::<()>::default(); let mut router = Router::<()>::default();