mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-11 12:31:25 +01:00
Add example for parsing body based on Content-Type
(#1320)
* Add example for parsing body based on `Content-Type` * format * Update examples/parse-body-based-on-content-type/src/main.rs Co-authored-by: Jonas Platte <jplatte+git@posteo.de> * fix copy/paste errors * rename type params Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
This commit is contained in:
parent
92f6b68390
commit
6d7c277700
2 changed files with 101 additions and 0 deletions
12
examples/parse-body-based-on-content-type/Cargo.toml
Normal file
12
examples/parse-body-based-on-content-type/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "example-parse-body-based-on-content-type"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
axum = { path = "../../axum" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
89
examples/parse-body-based-on-content-type/src/main.rs
Normal file
89
examples/parse-body-based-on-content-type/src/main.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
//! Provides a RESTful web server managing some Todos.
|
||||
//!
|
||||
//! Run with
|
||||
//!
|
||||
//! ```not_rust
|
||||
//! cd examples && cargo run -p example-parse-body-based-on-content-type
|
||||
//! ```
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
extract::FromRequest,
|
||||
http::{header::CONTENT_TYPE, Request, StatusCode},
|
||||
response::{IntoResponse, Response},
|
||||
routing::post,
|
||||
Form, Json, RequestExt, Router,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::EnvFilter::new(
|
||||
std::env::var("RUST_LOG").unwrap_or_else(|_| {
|
||||
"example_parse_body_based_on_content_type=debug,tower_http=debug".into()
|
||||
}),
|
||||
))
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
||||
let app = Router::new().route("/", post(handler));
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
tracing::debug!("listening on {}", addr);
|
||||
axum::Server::bind(&addr)
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Payload {
|
||||
foo: String,
|
||||
}
|
||||
|
||||
async fn handler(payload: JsonOrForm<Payload>) -> Response {
|
||||
match payload {
|
||||
JsonOrForm::Json(payload) => Json(payload).into_response(),
|
||||
JsonOrForm::Form(payload) => Form(payload).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
enum JsonOrForm<T, K = T> {
|
||||
Json(T),
|
||||
Form(K),
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S, B, T, U> FromRequest<S, B> for JsonOrForm<T, U>
|
||||
where
|
||||
B: Send + 'static,
|
||||
S: Send + Sync,
|
||||
Json<T>: FromRequest<(), B>,
|
||||
Form<U>: FromRequest<(), B>,
|
||||
T: 'static,
|
||||
U: 'static,
|
||||
{
|
||||
type Rejection = Response;
|
||||
|
||||
async fn from_request(req: Request<B>, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let content_type_header = req.headers().get(CONTENT_TYPE);
|
||||
let content_type = content_type_header.and_then(|value| value.to_str().ok());
|
||||
|
||||
if let Some(content_type) = content_type {
|
||||
if content_type.starts_with("application/json") {
|
||||
let Json(payload) = req.extract().await.map_err(IntoResponse::into_response)?;
|
||||
return Ok(Self::Json(payload));
|
||||
}
|
||||
|
||||
if content_type.starts_with("application/x-www-form-urlencoded") {
|
||||
let Form(payload) = req.extract().await.map_err(IntoResponse::into_response)?;
|
||||
return Ok(Self::Form(payload));
|
||||
}
|
||||
}
|
||||
|
||||
Err(StatusCode::UNSUPPORTED_MEDIA_TYPE.into_response())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue