mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-26 00:00:23 +02:00
Extend custom rejection examples (#1276)
* examples: Created new `error-handling` example
* examples(error-handling): Add error codes and responses
* examples(error-handling): `custom_extractor`
* examples(error-handling): `derive_from_request`
* examples(error-handling): Using POST instead of GET
* examples(error-handling): Using `thiserror` for `derive_from_request`
* examples(error-handling): Using `snake-case` for routes
* revert(error-handling): Use `From` impl instead of `thiserror`
refs: 3533d96215
* examples(error-handling): Removed chrono
* examples: merged `error-handling` and `customize-extractor-error`
* examples(customize-extractor-error): Improved error codes
* examples(customize-extractor-error): rustfmt
* examples(customize-extractor-error): Removed `matched-path` feature
Co-authored-by: David Pedersen <[email protected]>
* examples(customize-extractor-error): added `publish=false` to `Cargo.toml`
Co-authored-by: David Pedersen <[email protected]>
* examples(customize-extractor-error): Fix env filter
* examples(customize-extractor-error): Added README
* examples(customize-extractor-error): Added `with_rejection` comments
* examples(customize-extractor-error): Added `custom_extractor` comments
* examples(customize-extractor-error):Typo on `with_rejection`
* examples(customize-extractor-error): Added `boilerplate` con to `custom_extractor`
* examples(customize-extractor-error): Added `derive_from_request` comments
* examples(customize-extractor-error): typo impossible
* examples(customize-extractor-error): typos
* examples(customize-extractor-error): replaced `extensions` with `extract`
* examples(customize-extractor-error): typo `from`
Co-authored-by: David Pedersen <[email protected]>
Co-authored-by: David Pedersen <[email protected]>
This commit is contained in:
co-authored by
David Pedersen
parent
18dd830b84
commit
789f51ba1a
@@ -0,0 +1,60 @@
|
||||
//! Uses `axum_macros::FromRequest` to wrap another extractor and customize the
|
||||
//! rejection
|
||||
//!
|
||||
//! + Easy learning curve: Deriving `FromRequest` generates a `FromRequest`
|
||||
//! implementation for your type using another extractor. You only need
|
||||
//! to provide a `From` impl between the original rejection type and the
|
||||
//! target rejection. Crates like [`thiserror`] can provide such conversion
|
||||
//! using derive macros.
|
||||
//! - Boilerplate: Requires deriving `FromRequest` for every custom rejection
|
||||
//! - There are some known limitations: [FromRequest#known-limitations]
|
||||
//!
|
||||
//! [`thiserror`]: https://crates.io/crates/thiserror
|
||||
//! [FromRequest#known-limitations]: https://docs.rs/axum-macros/*/axum_macros/derive.FromRequest.html#known-limitations
|
||||
use axum::{extract::rejection::JsonRejection, http::StatusCode, response::IntoResponse};
|
||||
use axum_macros::FromRequest;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse {
|
||||
Json(dbg!(value));
|
||||
}
|
||||
|
||||
// create an extractor that internally uses `axum::Json` but has a custom rejection
|
||||
#[derive(FromRequest)]
|
||||
#[from_request(via(axum::Json), rejection(ApiError))]
|
||||
pub struct Json<T>(T);
|
||||
|
||||
// We create our own rejection type
|
||||
#[derive(Debug)]
|
||||
pub struct ApiError {
|
||||
code: StatusCode,
|
||||
message: String,
|
||||
}
|
||||
|
||||
// We implement `From<JsonRejection> for ApiError`
|
||||
impl From<JsonRejection> for ApiError {
|
||||
fn from(rejection: JsonRejection) -> Self {
|
||||
let code = match rejection {
|
||||
JsonRejection::JsonDataError(_) => StatusCode::UNPROCESSABLE_ENTITY,
|
||||
JsonRejection::JsonSyntaxError(_) => StatusCode::BAD_REQUEST,
|
||||
JsonRejection::MissingJsonContentType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
Self {
|
||||
code,
|
||||
message: rejection.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We implement `IntoResponse` so ApiError can be used as a response
|
||||
impl IntoResponse for ApiError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
let payload = json!({
|
||||
"message": self.message,
|
||||
"origin": "derive_from_request"
|
||||
});
|
||||
|
||||
(self.code, axum::Json(payload)).into_response()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user