mirror of
https://github.com/tokio-rs/axum.git
synced 2025-03-13 19:27:53 +01:00
examples: Replaced custom Json
extractor with WithRejection
This commit is contained in:
parent
3770e7b057
commit
d878eede18
2 changed files with 52 additions and 48 deletions
|
@ -6,6 +6,7 @@ publish = false
|
|||
|
||||
[dependencies]
|
||||
axum = { path = "../../axum" }
|
||||
axum-extra = { path = "../../axum-extra" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
|
|
|
@ -5,15 +5,15 @@
|
|||
//! ```
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
extract::{rejection::JsonRejection, FromRequest, RequestParts},
|
||||
extract::rejection::JsonRejection,
|
||||
http::StatusCode,
|
||||
routing::post,
|
||||
BoxError, Router,
|
||||
response::IntoResponse,
|
||||
routing::post, Json, Router,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::{json, Value};
|
||||
use std::{borrow::Cow, net::SocketAddr};
|
||||
use axum_extra::extract::WithRejection;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::net::SocketAddr;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[tokio::main]
|
||||
|
@ -38,7 +38,12 @@ async fn main() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
async fn handler(Json(user): Json<User>) {
|
||||
async fn handler(
|
||||
// `WithRejection` will extract `Json<User>` from the request. If the
|
||||
// extraction fails, a `MyRejection` will be created from `JsonResponse` and
|
||||
// returned to the client
|
||||
WithRejection(Json(user), _): WithRejection<Json<User>, MyRejection>
|
||||
) {
|
||||
dbg!(&user);
|
||||
}
|
||||
|
||||
|
@ -49,46 +54,44 @@ struct User {
|
|||
username: String,
|
||||
}
|
||||
|
||||
// We define our own `Json` extractor that customizes the error from `axum::Json`
|
||||
struct Json<T>(T);
|
||||
// Define your own custom rejection
|
||||
#[derive(Debug)]
|
||||
struct MyRejection {
|
||||
body: String,
|
||||
status: StatusCode,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B, T> FromRequest<B> for Json<T>
|
||||
where
|
||||
// these trait bounds are copied from `impl FromRequest for axum::Json`
|
||||
T: DeserializeOwned,
|
||||
B: axum::body::HttpBody + Send,
|
||||
B::Data: Send,
|
||||
B::Error: Into<BoxError>,
|
||||
{
|
||||
type Rejection = (StatusCode, axum::Json<Value>);
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
match axum::Json::<T>::from_request(req).await {
|
||||
Ok(value) => Ok(Self(value.0)),
|
||||
Err(rejection) => {
|
||||
// convert the error from `axum::Json` into whatever we want
|
||||
let (status, body): (_, Cow<'_, str>) = match rejection {
|
||||
JsonRejection::JsonDataError(err) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("Invalid JSON request: {}", err).into(),
|
||||
),
|
||||
JsonRejection::MissingJsonContentType(err) => {
|
||||
(StatusCode::BAD_REQUEST, err.to_string().into())
|
||||
}
|
||||
err => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unknown internal error: {}", err).into(),
|
||||
),
|
||||
};
|
||||
|
||||
Err((
|
||||
status,
|
||||
// we use `axum::Json` here to generate a JSON response
|
||||
// body but you can use whatever response you want
|
||||
axum::Json(json!({ "error": body })),
|
||||
))
|
||||
}
|
||||
}
|
||||
// `IntoResponse` is required for your custom rejection type
|
||||
impl IntoResponse for MyRejection {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
let Self { body, status } = self;
|
||||
(
|
||||
status,
|
||||
// we use `axum::Json` here to generate a JSON response
|
||||
// body but you can use whatever response you want
|
||||
axum::Json(json!({ "error": body })),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `From` for any Rejection type you want
|
||||
impl From<JsonRejection> for MyRejection {
|
||||
fn from(rejection: JsonRejection) -> Self {
|
||||
// convert the error from `axum::Json` into whatever we want
|
||||
let (status, body) = match rejection {
|
||||
JsonRejection::JsonDataError(err) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
format!("Invalid JSON request: {}", err),
|
||||
),
|
||||
JsonRejection::MissingJsonContentType(err) => {
|
||||
(StatusCode::BAD_REQUEST, err.to_string())
|
||||
}
|
||||
err => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unknown internal error: {}", err),
|
||||
),
|
||||
};
|
||||
Self { body, status }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue