diff --git a/src/actix.rs b/src/actix.rs index 88c7845..9d592cb 100644 --- a/src/actix.rs +++ b/src/actix.rs @@ -13,9 +13,10 @@ use actix_web4 as actix_web; use actix_web::dev::Payload; #[cfg(feature = "actix3")] use actix_web::HttpResponse; -use actix_web::{Error as ActixError, FromRequest, HttpRequest, ResponseError}; +use actix_web::{Error as ActixError, FromRequest, HttpRequest, ResponseError, web}; use futures::future::{ready, Ready, LocalBoxFuture, FutureExt}; use futures::StreamExt; +use serde::de::DeserializeOwned; use serde::de; use std::fmt; use std::fmt::{Debug, Display}; @@ -71,13 +72,17 @@ impl ResponseError for QsError { /// ``` pub struct QsQuery(T); -impl QsForm { - /// Unwrap into inner `T` value. - pub fn into_inner(self) -> T { +pub trait IntoInner { + fn into_inner(self) -> T; +} + +// let foo: T = QsQuery.into_inner() +impl IntoInner for QsQuery { + /// Unwrap into inner T value + fn into_inner(self) -> T { self.0 } } - impl Deref for QsQuery { type Target = T; @@ -92,13 +97,6 @@ impl DerefMut for QsQuery { } } -impl QsQuery { - /// Deconstruct to a inner value - pub fn into_inner(self) -> T { - self.0 - } -} - impl Debug for QsQuery { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -217,12 +215,53 @@ impl Default for QsQueryConfig { } } +// QS Form Extractor + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +/// Extract typed information from from the request's form data. +/// +/// ## Example +/// +/// ```rust +/// # #[macro_use] extern crate serde_derive; +/// # #[cfg(feature = "actix4")] +/// # use actix_web4 as actix_web; +/// # #[cfg(feature = "actix3")] +/// # use actix_web3 as actix_web; +/// # #[cfg(feature = "actix2")] +/// # use actix_web2 as actix_web; +/// use actix_web::{web, App, HttpResponse}; +/// use serde_qs::actix::QsForm; +/// +/// #[derive(Deserialize)] +/// pub struct UsersFilter { +/// id: Vec, +/// } +/// +/// // Use `QsForm` extractor for Form information. +/// // Content-Type: application/x-www-form-urlencoded +/// // The correct request payload for this handler would be `id[]=1124&id[]=88` +/// async fn filter_users(info: QsForm) -> HttpResponse { +/// HttpResponse::Ok().body( +/// info.id.iter().map(|i| i.to_string()).collect::>().join(", ") +/// ) +/// } +/// +/// fn main() { +/// let app = App::new().service( +/// web::resource("/users") +/// .route(web::get().to(filter_users))); +/// } +/// ``` + + #[derive(Debug)] pub struct QsForm(T); -impl QsForm { - /// Unwrap into inner `T` value. - pub fn into_inner(self) -> T { +// let foo: T = QsQuery.into_inner() +impl IntoInner for QsForm { + /// Unwrap into inner T value + fn into_inner(self) -> T { self.0 } } @@ -244,6 +283,49 @@ impl DerefMut for QsForm { // private fields on QsQueryConfig prevent its reuse here, so a new struct // is defined +/// Form extractor configuration +/// +/// ```rust +/// # #[macro_use] extern crate serde_derive; +/// # #[cfg(feature = "actix4")] +/// # use actix_web4 as actix_web; +/// # #[cfg(feature = "actix3")] +/// # use actix_web3 as actix_web; +/// # #[cfg(feature = "actix2")] +/// # use actix_web2 as actix_web; +/// use actix_web::{error, web, App, FromRequest, HttpResponse}; +/// use serde_qs::actix::QsQuery; +/// use serde_qs::Config as QsConfig; +/// use serde_qs::actix::QsFormConfig; +/// +/// #[derive(Deserialize)] +/// struct Info { +/// username: String, +/// } +/// +/// /// deserialize `Info` from request's payload +/// async fn index(info: QsForm) -> HttpResponse { +/// use serde_qs::actix::QsForm; +/// HttpResponse::Ok().body( +/// format!("Welcome {}!", info.username) +/// ) +/// } +/// +/// fn main() { +/// let qs_config = QsFormConfig::default() +/// .error_handler(|err, req| { // <- create custom error response +/// error::InternalError::from_response( +/// err, HttpResponse::Conflict().finish()).into() +/// }) +/// .qs_config(QsConfig::default()); +/// +/// let app = App::new().service( +/// web::resource("/index.html").app_data(qs_config) +/// .route(web::post().to(index)) +/// ); +/// } +/// ``` + pub struct QsFormConfig { ehandler: Option ActixError + Send + Sync>>, qs_config: QsConfig, @@ -275,6 +357,7 @@ impl Default for QsFormConfig { } } +// // See: // - https://github.com/actix/actix-web/blob/master/src/types/form.rs // - https://github.com/samscott89/serde_qs/blob/main/src/actix.rs @@ -292,12 +375,12 @@ where async move { let mut bytes = web::BytesMut::new(); - + while let Some(item) = stream.next().await { bytes.extend_from_slice(&item.unwrap()); } - - let query_config = req_clone.app_data::().clone(); + + let query_config = req_clone.app_data::().clone(); let error_handler = query_config.map(|c| c.ehandler.clone()).unwrap_or(None); let default_qsconfig = QsConfig::default();