mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-08 00:00:24 +02:00
examples(error-handling): custom_extractor
This commit is contained in:
@@ -6,7 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { path = "../../axum" }
|
axum = { path = "../../axum", features=["matched-path"] }
|
||||||
axum-extra = { path = "../../axum-extra" }
|
axum-extra = { path = "../../axum-extra" }
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
use axum::extract::MatchedPath;
|
||||||
|
use axum::{
|
||||||
|
async_trait,
|
||||||
|
extract::{rejection::JsonRejection, FromRequest, RequestParts},
|
||||||
|
http::StatusCode,
|
||||||
|
response::IntoResponse,
|
||||||
|
BoxError,
|
||||||
|
};
|
||||||
|
use chrono::Utc;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse {
|
||||||
|
Json(dbg!(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We define our own `Json` extractor that customizes the error from `axum::Json`
|
||||||
|
pub struct Json<T>(T);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<S, B, T> FromRequest<S, B> for Json<T>
|
||||||
|
where
|
||||||
|
S: Send + Sync,
|
||||||
|
// 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<S, 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 path = req
|
||||||
|
.extensions()
|
||||||
|
.get::<MatchedPath>()
|
||||||
|
.map(|x| x.as_str().to_owned());
|
||||||
|
|
||||||
|
let payload = json!({
|
||||||
|
"message": rejection.to_string(),
|
||||||
|
"timestamp": Utc::now(),
|
||||||
|
"origin": "custom_extractor",
|
||||||
|
"path": path,
|
||||||
|
});
|
||||||
|
|
||||||
|
let code = match rejection {
|
||||||
|
JsonRejection::JsonDataError(_) | JsonRejection::MissingJsonContentType(_) => {
|
||||||
|
StatusCode::BAD_REQUEST
|
||||||
|
}
|
||||||
|
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
};
|
||||||
|
Err((code, axum::Json(payload)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,23 @@
|
|||||||
mod with_rejection;
|
mod with_rejection;
|
||||||
|
mod custom_extractor;
|
||||||
|
|
||||||
|
use axum::{routing::get, Router, Server};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use axum::{Server, Router, routing::get};
|
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
tracing_subscriber::registry()
|
tracing_subscriber::registry()
|
||||||
.with(tracing_subscriber::EnvFilter::new(
|
.with(tracing_subscriber::EnvFilter::new(
|
||||||
std::env::var("RUST_LOG")
|
std::env::var("RUST_LOG").unwrap_or_else(|_| "error_handling=debug".into()),
|
||||||
.unwrap_or_else(|_| "error_handling=debug".into()),
|
|
||||||
))
|
))
|
||||||
.with(tracing_subscriber::fmt::layer())
|
.with(tracing_subscriber::fmt::layer())
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
// Build our application with some routes
|
// Build our application with some routes
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/withRejection", get(with_rejection::handler));
|
.route("/withRejection", get(with_rejection::handler))
|
||||||
|
.route("/customExtractor", get(custom_extractor::handler));
|
||||||
|
|
||||||
// Run our application
|
// Run our application
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
|
|||||||
Reference in New Issue
Block a user