pub trait Handler<T, B = Body>: Clone + Send + Sized + 'static {
type Future: Future<Output = Response> + Send + 'static;
fn call(self, req: Request<B>) -> Self::Future;
fn layer<L>(self, layer: L) -> Layered<L::Service, T>
where
L: Layer<IntoService<Self, T, B>>,
{ ... }
fn into_service(self) -> IntoService<Self, T, B> { ... }
fn into_make_service(self) -> IntoMakeService<IntoService<Self, T, B>> { ... }
fn into_make_service_with_connect_info<C>(
self
) -> IntoMakeServiceWithConnectInfo<IntoService<Self, T, B>, C> { ... }
}
Expand description
Trait for async functions that can be used to handle requests.
You shouldn’t need to depend on this trait directly. It is automatically implemented to closures of the right types.
See the module docs for more details.
Debugging handler type errors
For a function to be used as a handler it must implement the Handler
trait.
axum provides blanket implementations for functions that:
- Are
async fn
s. - Take no more than 16 arguments that all implement
FromRequest
. - Returns something that implements
IntoResponse
. - If a closure is used it must implement
Clone + Send
and be'static
. - Returns a future that is
Send
. The most common way to accidentally make a future!Send
is to hold a!Send
type across an await.
Unfortunately Rust gives poor error messages if you try to use a function
that doesn’t quite match what’s required by Handler
.
You might get an error like this:
error[E0277]: the trait bound `fn(bool) -> impl Future {handler}: Handler<_, _>` is not satisfied
--> src/main.rs:13:44
|
13 | let app = Router::new().route("/", get(handler));
| ^^^^^^^ the trait `Handler<_, _>` is not implemented for `fn(bool) -> impl Future {handler}`
|
::: axum/src/handler/mod.rs:116:8
|
116 | H: Handler<T, B>,
| ------------- required by this bound in `axum::routing::get`
This error doesn’t tell you why your function doesn’t implement
Handler
. It’s possible to improve the error with the debug_handler
proc-macro from the axum-macros crate.
Required Associated Types
Required Methods
Provided Methods
Apply a tower::Layer
to the handler.
All requests to the handler will be processed by the layer’s corresponding middleware.
This can be used to add additional processing to a request for a single handler.
Note this differs from routing::Router::layer
which adds a middleware to a group of routes.
If you’re applying middleware that produces errors you have to handle the errors so they’re converted into responses. You can learn more about doing that here.
Example
Adding the tower::limit::ConcurrencyLimit
middleware to a handler
can be done like so:
use axum::{
routing::get,
handler::Handler,
Router,
};
use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};
async fn handler() { /* ... */ }
let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64));
let app = Router::new().route("/", get(layered_handler));
sourcefn into_service(self) -> IntoService<Self, T, B>
fn into_service(self) -> IntoService<Self, T, B>
Convert the handler into a Service
.
This is commonly used together with Router::fallback
:
use axum::{
Server,
handler::Handler,
http::{Uri, Method, StatusCode},
response::IntoResponse,
routing::{get, Router},
};
use tower::make::Shared;
use std::net::SocketAddr;
async fn handler(method: Method, uri: Uri) -> (StatusCode, String) {
(StatusCode::NOT_FOUND, format!("Nothing to see at {} {}", method, uri))
}
let app = Router::new()
.route("/", get(|| async {}))
.fallback(handler.into_service());
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
.serve(app.into_make_service())
.await?;
sourcefn into_make_service(self) -> IntoMakeService<IntoService<Self, T, B>>
fn into_make_service(self) -> IntoMakeService<IntoService<Self, T, B>>
Convert the handler into a MakeService
.
This allows you to serve a single handler if you don’t need any routing:
use axum::{
Server, handler::Handler, http::{Uri, Method}, response::IntoResponse,
};
use std::net::SocketAddr;
async fn handler(method: Method, uri: Uri, body: String) -> String {
format!("received `{} {}` with body `{:?}`", method, uri, body)
}
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
.serve(handler.into_make_service())
.await?;
sourcefn into_make_service_with_connect_info<C>(
self
) -> IntoMakeServiceWithConnectInfo<IntoService<Self, T, B>, C>
fn into_make_service_with_connect_info<C>(
self
) -> IntoMakeServiceWithConnectInfo<IntoService<Self, T, B>, C>
Convert the handler into a MakeService
which stores information
about the incoming connection.
See Router::into_make_service_with_connect_info
for more details.
use axum::{
Server,
handler::Handler,
response::IntoResponse,
extract::ConnectInfo,
};
use std::net::SocketAddr;
async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
format!("Hello {}", addr)
}
Server::bind(&SocketAddr::from(([127, 0, 0, 1], 3000)))
.serve(handler.into_make_service_with_connect_info::<SocketAddr>())
.await?;