Skip to content

Commit

Permalink
Implement IntoResponse for Form (#1095)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidpdrsn committed Jun 17, 2022
1 parent 93251fa commit 2f64064
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 25 deletions.
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Expand Up @@ -9,9 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **added:** Support resolving host name via `Forwarded` header in `Host`
extractor ([#1078])
- **added:** Implement `IntoResponse` for `Form` ([#1095])
- **change:** axum's MSRV is now 1.56 ([#1098])

[#1078]: https://github.com/tokio-rs/axum/pull/1078
[#1095]: https://github.com/tokio-rs/axum/pull/1095
[#1098]: https://github.com/tokio-rs/axum/pull/1098

# 0.5.7 (08. June, 2022)
Expand Down
7 changes: 2 additions & 5 deletions axum/src/extract/mod.rs
Expand Up @@ -39,11 +39,8 @@ pub use crate::Json;
pub use crate::Extension;

#[cfg(feature = "form")]
mod form;

#[cfg(feature = "form")]
#[doc(inline)]
pub use self::form::Form;
#[doc(no_inline)]
pub use crate::form::Form;

#[cfg(feature = "matched-path")]
mod matched_path;
Expand Down
67 changes: 47 additions & 20 deletions axum/src/extract/form.rs → axum/src/form.rs
@@ -1,24 +1,23 @@
use super::{has_content_type, rejection::*, FromRequest, RequestParts};
use crate::body::{Bytes, HttpBody};
use crate::extract::{has_content_type, rejection::*, FromRequest, RequestParts};
use crate::BoxError;
use async_trait::async_trait;
use http::Method;
use axum_core::response::{IntoResponse, Response};
use http::header::CONTENT_TYPE;
use http::{Method, StatusCode};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::ops::Deref;

/// Extractor that deserializes `application/x-www-form-urlencoded` requests
/// into some type.
/// URL encoded extractor and response.
///
/// `T` is expected to implement [`serde::Deserialize`].
/// # As extractor
///
/// # Example
/// If used as an extractor `Form` will deserialize `application/x-www-form-urlencoded` request
/// bodies into some target type via [`serde::Deserialize`].
///
/// ```rust,no_run
/// use axum::{
/// extract::Form,
/// routing::post,
/// Router,
/// };
/// ```rust
/// use axum::Form;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
Expand All @@ -27,19 +26,31 @@ use std::ops::Deref;
/// password: String,
/// }
///
/// async fn accept_form(form: Form<SignUp>) {
/// let sign_up: SignUp = form.0;
///
/// async fn accept_form(Form(sign_up): Form<SignUp>) {
/// // ...
/// }
/// ```
///
/// Note that `Content-Type: multipart/form-data` requests are not supported. Use [`Multipart`]
/// instead.
///
/// # As response
///
/// ```rust
/// use axum::Form;
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Payload {
/// value: String,
/// }
///
/// let app = Router::new().route("/sign_up", post(accept_form));
/// # async {
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
/// # };
/// async fn handler() -> Form<Payload> {
/// Form(Payload { value: "foo".to_owned() })
/// }
/// ```
///
/// Note that `Content-Type: multipart/form-data` requests are not supported.
/// [`Multipart`]: crate::extract::Multipart
#[cfg_attr(docsrs, doc(cfg(feature = "form")))]
#[derive(Debug, Clone, Copy, Default)]
pub struct Form<T>(pub T);
Expand Down Expand Up @@ -74,6 +85,22 @@ where
}
}

impl<T> IntoResponse for Form<T>
where
T: Serialize,
{
fn into_response(self) -> Response {
match serde_urlencoded::to_string(&self.0) {
Ok(body) => (
[(CONTENT_TYPE, mime::APPLICATION_WWW_FORM_URLENCODED.as_ref())],
body,
)
.into_response(),
Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response(),
}
}
}

impl<T> Deref for Form<T> {
type Target = T;

Expand Down
6 changes: 6 additions & 0 deletions axum/src/lib.rs
Expand Up @@ -395,6 +395,8 @@
pub(crate) mod macros;

mod extension;
#[cfg(feature = "form")]
mod form;
#[cfg(feature = "json")]
mod json;
#[cfg(feature = "headers")]
Expand Down Expand Up @@ -434,5 +436,9 @@ pub use self::routing::Router;
#[cfg(feature = "headers")]
pub use self::typed_header::TypedHeader;

#[doc(inline)]
#[cfg(feature = "headers")]
pub use form::Form;

#[doc(inline)]
pub use axum_core::{BoxError, Error};
4 changes: 4 additions & 0 deletions axum/src/response/mod.rs
Expand Up @@ -15,6 +15,10 @@ pub use crate::Json;
#[cfg(feature = "headers")]
pub use crate::TypedHeader;

#[cfg(feature = "form")]
#[doc(no_inline)]
pub use crate::form::Form;

#[doc(no_inline)]
pub use crate::Extension;

Expand Down

0 comments on commit 2f64064

Please sign in to comment.