Module extract
Types and traits for extracting data from requests.
Intro
A handler function is an async function that takes any number of
"extractors" as arguments. An extractor is a type that implements
FromRequest or FromRequestParts.
For example, Json is an extractor that consumes the request body and
deserializes it as JSON into some target type:
use ;
use Deserialize;
async
let app = new.route;
# let _: Router = app;
Common extractors
Some commonly used extractors are:
use ;
use Value;
use HashMap;
// `Path` gives you the path parameters and deserializes them. See its docs for
// more details
async
// `Query` gives you the query parameters and deserializes them.
async
// `HeaderMap` gives you all the headers
async
// `String` consumes the request body and ensures it is valid utf-8
async
// `Bytes` gives you the raw request body
async
// We've already seen `Json` for parsing the request body as json
async
// `Request` gives you the whole request for maximum control
async
// `Extension` extracts data from "request extensions"
// This is commonly used to share state with handlers
async
let app = new
.route
.route
.route
.route
.route
.route
.route;
# let _: Router = app;
Applying multiple extractors
You can also apply multiple extractors:
use ;
use Uuid;
use Deserialize;
let app = new.route;
async
# let _: Router = app;
The order of extractors
Extractors always run in the order of the function parameters that is from left to right.
The request body is an asynchronous stream that can only be consumed once. Therefore you can only have one extractor that consumes the request body. axum enforces this by requiring such extractors to be the last argument your handler takes.
For example
use ;
#
#
#
async
#
# let _: MethodRouter = get;
We get a compile error if String isn't the last extractor:
use Method;
async
#
# let _: MethodRouter = get;
This also means you cannot consume the request body twice:
use Json;
use Deserialize;
async
#
# let _: MethodRouter = get;
axum enforces this by requiring the last extractor implements FromRequest
and all others implement FromRequestParts.
Handling extractor rejections
If you want to handle the case of an extractor failing within a specific
handler, you can wrap it in Result, with the error being the rejection type
of the extractor:
use ;
use Value;
async
let app = new.route;
# let _: Router = app;
Optional extractors
Some extractors implement OptionalFromRequestParts in addition to
FromRequestParts, or OptionalFromRequest in addition to FromRequest.
These extractors can be used inside of Option. It depends on the particular
OptionalFromRequestParts or OptionalFromRequest implementation what this
does: For example for TypedHeader from axum-extra, you get None if the
header you're trying to extract is not part of the request, but if the header
is present and fails to parse, the request is rejected.
use ;
use ;
use Value;
async
let app = new.route;
# let _: Router = app;
Customizing extractor responses
If an extractor fails it will return a response with the error and your handler will not be called. To customize the error response you have two options:
- Use
Result<T, T::Rejection>as your extractor like shown in "Optional extractors". This works well if you're only using the extractor in a single handler. - Create your own extractor that in its
FromRequestimplementation calls one of axum's built in extractors but returns a different response for rejections. See the customize-extractor-error example for more details.
Accessing inner errors
axum's built-in extractors don't directly expose the inner error. This gives us more flexibility and allows us to change internal implementations without breaking the public API.
For example that means while Json is implemented using serde_json it
doesn't directly expose the serde_json::Error that's contained in
JsonRejection::JsonDataError. However it is still possible to access via
methods from [std::error::Error]:
use Error;
use ;
use ;
async
// attempt to extract the inner `serde_path_to_error::Error<serde_json::Error>`,
// if that succeeds we can provide a more specific error.
//
// `Json` uses `serde_path_to_error` so the error will be wrapped in `serde_path_to_error::Error`.
// attempt to downcast `err` into a `T` and if that fails recursively try and
// downcast `err`'s source
#
#
# async
Note that while this approach works it might break in the future if axum changes its implementation to use a different error type internally. Such changes might happen without major breaking versions.
Defining custom extractors
You can also define your own extractors by implementing either
FromRequestParts or FromRequest.
Implementing FromRequestParts
Implement FromRequestParts if your extractor doesn't need access to the
request body:
use ;
;
async
let app = new.route;
# let _: Router = app;
Implementing FromRequest
If your extractor needs to consume the request body you must implement FromRequest
use ;
;
async
let app = new.route;
# let _: Router = app;
Cannot implement both FromRequest and FromRequestParts
Note that you will make your extractor unusable by implementing both
FromRequest and FromRequestParts directly for the same type, unless it is
wrapping another extractor:
use ;
use Infallible;
// Some extractor that doesn't wrap another extractor
;
// `MyExtractor` implements both `FromRequest`
// and `FromRequestParts`
let app = new.route;
# let _: Router = app;
Accessing other extractors in FromRequest or FromRequestParts implementations
When defining custom extractors you often need to access another extractor in your implementation.
use ;
async
let state = State ;
let app = new.route.layer;
# let _: Router = app;
Request body limits
For security reasons, Bytes will, by default, not accept bodies larger than
2MB. This also applies to extractors that uses Bytes internally such as
String, Json, and Form.
For more details, including how to disable this limit, see DefaultBodyLimit.
Wrapping extractors
If you want write an extractor that generically wraps another extractor (that
may or may not consume the request body) you should implement both
FromRequest and [FromRequestParts]:
use ;
use ;
// an extractor that wraps another and measures how long time it takes to run
// we must implement both `FromRequestParts`
// and `FromRequest`
async
# let _: MethodRouter = get;
Logging rejections
All built-in extractors will log rejections for easier debugging. To see the
logs, enable the tracing feature for axum (enabled by default) and the
axum::rejection=trace tracing target, for example with
RUST_LOG=info,axum::rejection=trace cargo run.
Modules
- connect_info Extractor for getting connection information from a client.
-
path
Extractor that will get captures from the URL and parse them using
serde. - rejection Rejection response types.
-
ws
Handle WebSocket connections.
[
StreamExt::split]: [StreamExt::split]: https://docs.rs/futures/0.3.17/futures/stream/trait.StreamExt.html#method.split