Derive Macro axum_macros::FromRequest
source · [−]#[derive(FromRequest)]
{
// Attributes available to this derive:
#[from_request]
}
Expand description
Derive an implementation of FromRequest
.
Supports generating two kinds of implementations:
- One that extracts each field individually.
- Another that extracts the whole type at once via another extractor.
Each field individually
By default #[derive(FromRequest)]
will call FromRequest::from_request
for each field:
use axum_macros::FromRequest;
use axum::{
extract::{Extension, TypedHeader},
headers::ContentType,
body::Bytes,
};
#[derive(FromRequest)]
struct MyExtractor {
state: Extension<State>,
content_type: TypedHeader<ContentType>,
request_body: Bytes,
}
#[derive(Clone)]
struct State {
// ...
}
async fn handler(extractor: MyExtractor) {}
This requires that each field is an extractor (i.e. implements FromRequest
).
Extracting via another extractor
You can use #[from_request(via(...))]
to extract a field via another extractor, meaning the
field itself doesn’t need to implement FromRequest
:
use axum_macros::FromRequest;
use axum::{
extract::{Extension, TypedHeader},
headers::ContentType,
body::Bytes,
};
#[derive(FromRequest)]
struct MyExtractor {
// This will extracted via `Extension::<State>::from_request`
#[from_request(via(Extension))]
state: State,
// and this via `TypedHeader::<ContentType>::from_request`
#[from_request(via(TypedHeader))]
content_type: ContentType,
// Can still be combined with other extractors
request_body: Bytes,
}
#[derive(Clone)]
struct State {
// ...
}
async fn handler(extractor: MyExtractor) {}
Note this requires the via extractor to be a generic newtype struct (a tuple struct with
exactly one public field) that implements FromRequest
:
pub struct ViaExtractor<T>(pub T);
// impl<T, B> FromRequest<B> for ViaExtractor<T> { ... }
More complex via extractors are not supported and require writing a manual implementation.
Optional fields
#[from_request(via(...))]
supports Option<_>
and Result<_, _>
to make fields optional:
use axum_macros::FromRequest;
use axum::{
extract::{TypedHeader, rejection::TypedHeaderRejection},
headers::{ContentType, UserAgent},
};
#[derive(FromRequest)]
struct MyExtractor {
// This will extracted via `Option::<TypedHeader<ContentType>>::from_request`
#[from_request(via(TypedHeader))]
content_type: Option<ContentType>,
// This will extracted via
// `Result::<TypedHeader<UserAgent>, TypedHeaderRejection>::from_request`
#[from_request(via(TypedHeader))]
user_agent: Result<UserAgent, TypedHeaderRejection>,
}
async fn handler(extractor: MyExtractor) {}
The rejection
A rejection enum is also generated. It has a variant for each field:
use axum_macros::FromRequest;
use axum::{
extract::{Extension, TypedHeader},
headers::ContentType,
body::Bytes,
};
#[derive(FromRequest)]
struct MyExtractor {
#[from_request(via(Extension))]
state: State,
#[from_request(via(TypedHeader))]
content_type: ContentType,
request_body: Bytes,
}
// also generates
//
// #[derive(Debug)]
// enum MyExtractorRejection {
// State(ExtensionRejection),
// ContentType(TypedHeaderRejection),
// RequestBody(BytesRejection),
// }
//
// impl axum::response::IntoResponse for MyExtractor { ... }
//
// impl std::fmt::Display for MyExtractor { ... }
//
// impl std::error::Error for MyExtractor { ... }
#[derive(Clone)]
struct State {
// ...
}
The rejection’s std::error::Error::source
implementation returns the inner rejection. This
can be used to access source errors for example to customize rejection responses. Note this
means the inner rejection types must themselves implement std::error::Error
. All extractors
in axum does this.
You can opt out of this using #[from_request(rejection_derive(...))]
:
use axum_macros::FromRequest;
use axum::{
extract::{FromRequest, RequestParts},
http::StatusCode,
headers::ContentType,
body::Bytes,
async_trait,
};
#[derive(FromRequest)]
#[from_request(rejection_derive(!Display, !Error))]
struct MyExtractor {
other: OtherExtractor,
}
struct OtherExtractor;
#[async_trait]
impl<B> FromRequest<B> for OtherExtractor
where
B: Send + 'static,
{
// this rejection doesn't implement `Display` and `Error`
type Rejection = (StatusCode, String);
async fn from_request(_req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
// ...
}
}
The whole type at once
By using #[from_request(via(...))]
on the container you can extract the whole type at once,
instead of each field individually:
use axum_macros::FromRequest;
use axum::extract::Extension;
// This will extracted via `Extension::<State>::from_request`
#[derive(Clone, FromRequest)]
#[from_request(via(Extension))]
struct State {
// ...
}
async fn handler(state: State) {}
The rejection will be the “via extractors”’s rejection. For the previous example that would be
axum::extract::rejection::ExtensionRejection
.
Known limitations
Generics are currently not supported:
#[derive(axum_macros::FromRequest)]
struct MyExtractor<T> {
thing: Option<T>,
}