Support customizing rejections for #[derive(TypedPath)] (#1012)

* Support customizing rejections for `#[derive(TypedPath)]`

* changelog

* clean up
This commit is contained in:
David Pedersen
2022-05-17 21:36:05 +02:00
committed by GitHub
parent b215a87a19
commit 5948cde6c1
5 changed files with 227 additions and 23 deletions
+65
View File
@@ -140,12 +140,77 @@ use http::Uri;
/// );
/// ```
///
/// ## Customizing the rejection
///
/// By default the rejection used in the [`FromRequest`] implemetation will be [`PathRejection`].
///
/// That can be customized using `#[typed_path("...", rejection(YourType))]`:
///
/// ```
/// use serde::Deserialize;
/// use axum_extra::routing::TypedPath;
/// use axum::{
/// response::{IntoResponse, Response},
/// extract::rejection::PathRejection,
/// };
///
/// #[derive(TypedPath, Deserialize)]
/// #[typed_path("/users/:id", rejection(UsersMemberRejection))]
/// struct UsersMember {
/// id: String,
/// }
///
/// struct UsersMemberRejection;
///
/// // Your rejection type must implement `From<PathRejection>`.
/// //
/// // Here you can grab whatever details from the inner rejection
/// // that you need.
/// impl From<PathRejection> for UsersMemberRejection {
/// fn from(rejection: PathRejection) -> Self {
/// # UsersMemberRejection
/// // ...
/// }
/// }
///
/// // Your rejection must implement `IntoResponse`, like all rejections.
/// impl IntoResponse for UsersMemberRejection {
/// fn into_response(self) -> Response {
/// # ().into_response()
/// // ...
/// }
/// }
/// ```
///
/// The `From<PathRejection>` requirement only applies if your typed path is a struct with named
/// fields or a tuple struct. For unit structs your rejection type must implement `Default`:
///
/// ```
/// use axum_extra::routing::TypedPath;
/// use axum::response::{IntoResponse, Response};
///
/// #[derive(TypedPath)]
/// #[typed_path("/users", rejection(UsersCollectionRejection))]
/// struct UsersCollection;
///
/// #[derive(Default)]
/// struct UsersCollectionRejection;
///
/// impl IntoResponse for UsersCollectionRejection {
/// fn into_response(self) -> Response {
/// # ().into_response()
/// // ...
/// }
/// }
/// ```
///
/// [`FromRequest`]: axum::extract::FromRequest
/// [`RouterExt::typed_get`]: super::RouterExt::typed_get
/// [`RouterExt::typed_post`]: super::RouterExt::typed_post
/// [`Path`]: axum::extract::Path
/// [`Display`]: std::fmt::Display
/// [`Deserialize`]: serde::Deserialize
/// [`PathRejection`]: axum::extract::rejection::PathRejection
pub trait TypedPath: std::fmt::Display {
/// The path with optional captures such as `/users/:id`.
const PATH: &'static str;