blob: 5087ac7c937f4a9e9eac718e3ca42db980da2931 [file] [log] [blame]
//! Async functions that can be used to handle requests.
//!
#![doc = include_str!("../docs/handlers_intro.md")]
//!
//! Some examples of handlers:
//!
//! ```rust
//! use axum::{body::Bytes, http::StatusCode};
//!
//! // Handler that immediately returns an empty `200 OK` response.
//! async fn unit_handler() {}
//!
//! // Handler that immediately returns an empty `200 OK` response with a plain
//! // text body.
//! async fn string_handler() -> String {
//! "Hello, World!".to_string()
//! }
//!
//! // Handler that buffers the request body and returns it.
//! //
//! // This works because `Bytes` implements `FromRequest`
//! // and therefore can be used as an extractor.
//! //
//! // `String` and `StatusCode` both implement `IntoResponse` and
//! // therefore `Result<String, StatusCode>` also implements `IntoResponse`
//! async fn echo(body: Bytes) -> Result<String, StatusCode> {
//! if let Ok(string) = String::from_utf8(body.to_vec()) {
//! Ok(string)
//! } else {
//! Err(StatusCode::BAD_REQUEST)
//! }
//! }
//! ```
//!
//! Instead of a direct `StatusCode`, it makes sense to use intermediate error type
//! that can ultimately be converted to `Response`. This allows using `?` operator
//! in handlers. See those examples:
//!
//! * [`anyhow-error-response`][anyhow] for generic boxed errors
//! * [`error-handling-and-dependency-injection`][ehdi] for application-specific detailed errors
//!
//! [anyhow]: https://github.com/tokio-rs/axum/blob/main/examples/anyhow-error-response/src/main.rs
//! [ehdi]: https://github.com/tokio-rs/axum/blob/main/examples/error-handling-and-dependency-injection/src/main.rs
//!
#![doc = include_str!("../docs/debugging_handler_type_errors.md")]
#[cfg(feature = "tokio")]
use crate::extract::connect_info::IntoMakeServiceWithConnectInfo;
use crate::{
body::Body,
extract::{FromRequest, FromRequestParts},
response::{IntoResponse, Response},
routing::IntoMakeService,
};
use http::Request;
use std::{convert::Infallible, fmt, future::Future, marker::PhantomData, pin::Pin};
use tower::ServiceExt;
use tower_layer::Layer;
use tower_service::Service;
pub mod future;
mod service;
pub use self::service::HandlerService;
/// 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](crate::handler) for more details.
///
/// # Converting `Handler`s into [`Service`]s
///
/// To convert `Handler`s into [`Service`]s you have to call either
/// [`HandlerWithoutStateExt::into_service`] or [`Handler::with_state`]:
///
/// ```
/// use tower::Service;
/// use axum::{
/// extract::State,
/// body::Body,
/// http::Request,
/// handler::{HandlerWithoutStateExt, Handler},
/// };
///
/// // this handler doesn't require any state
/// async fn one() {}
/// // so it can be converted to a service with `HandlerWithoutStateExt::into_service`
/// assert_service(one.into_service());
///
/// // this handler requires state
/// async fn two(_: State<String>) {}
/// // so we have to provide it
/// let handler_with_state = two.with_state(String::new());
/// // which gives us a `Service`
/// assert_service(handler_with_state);
///
/// // helper to check that a value implements `Service`
/// fn assert_service<S>(service: S)
/// where
/// S: Service<Request<Body>>,
/// {}
/// ```
#[doc = include_str!("../docs/debugging_handler_type_errors.md")]
///
/// # Handlers that aren't functions
///
/// The `Handler` trait is also implemented for `T: IntoResponse`. That allows easily returning
/// fixed data for routes:
///
/// ```
/// use axum::{
/// Router,
/// routing::{get, post},
/// Json,
/// http::StatusCode,
/// };
/// use serde_json::json;
///
/// let app = Router::new()
/// // respond with a fixed string
/// .route("/", get("Hello, World!"))
/// // or return some mock data
/// .route("/users", post((
/// StatusCode::CREATED,
/// Json(json!({ "id": 1, "username": "alice" })),
/// )));
/// # let _: Router = app;
/// ```
#[cfg_attr(
nightly_error_messages,
rustc_on_unimplemented(
note = "Consider using `#[axum::debug_handler]` to improve the error message"
)
)]
pub trait Handler<T, S, B = Body>: Clone + Send + Sized + 'static {
/// The type of future calling this handler returns.
type Future: Future<Output = Response> + Send + 'static;
/// Call the handler with the given request.
fn call(self, req: Request<B>, state: S) -> Self::Future;
/// 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`](crate::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](crate::error_handling).
///
/// # Example
///
/// Adding the [`tower::limit::ConcurrencyLimit`] middleware to a handler
/// can be done like so:
///
/// ```rust
/// 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));
/// # async {
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
/// # };
/// ```
fn layer<L, NewReqBody>(self, layer: L) -> Layered<L, Self, T, S, B, NewReqBody>
where
L: Layer<HandlerService<Self, T, S, B>> + Clone,
L::Service: Service<Request<NewReqBody>>,
{
Layered {
layer,
handler: self,
_marker: PhantomData,
}
}
/// Convert the handler into a [`Service`] by providing the state
fn with_state(self, state: S) -> HandlerService<Self, T, S, B> {
HandlerService::new(self, state)
}
}
impl<F, Fut, Res, S, B> Handler<((),), S, B> for F
where
F: FnOnce() -> Fut + Clone + Send + 'static,
Fut: Future<Output = Res> + Send,
Res: IntoResponse,
B: Send + 'static,
{
type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
fn call(self, _req: Request<B>, _state: S) -> Self::Future {
Box::pin(async move { self().await.into_response() })
}
}
macro_rules! impl_handler {
(
[$($ty:ident),*], $last:ident
) => {
#[allow(non_snake_case, unused_mut)]
impl<F, Fut, S, B, Res, M, $($ty,)* $last> Handler<(M, $($ty,)* $last,), S, B> for F
where
F: FnOnce($($ty,)* $last,) -> Fut + Clone + Send + 'static,
Fut: Future<Output = Res> + Send,
B: Send + 'static,
S: Send + Sync + 'static,
Res: IntoResponse,
$( $ty: FromRequestParts<S> + Send, )*
$last: FromRequest<S, B, M> + Send,
{
type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
fn call(self, req: Request<B>, state: S) -> Self::Future {
Box::pin(async move {
let (mut parts, body) = req.into_parts();
let state = &state;
$(
let $ty = match $ty::from_request_parts(&mut parts, state).await {
Ok(value) => value,
Err(rejection) => return rejection.into_response(),
};
)*
let req = Request::from_parts(parts, body);
let $last = match $last::from_request(req, state).await {
Ok(value) => value,
Err(rejection) => return rejection.into_response(),
};
let res = self($($ty,)* $last,).await;
res.into_response()
})
}
}
};
}
all_the_tuples!(impl_handler);
mod private {
// Marker type for `impl<T: IntoResponse> Handler for T`
#[allow(missing_debug_implementations)]
pub enum IntoResponseHandler {}
}
impl<T, S, B> Handler<private::IntoResponseHandler, S, B> for T
where
T: IntoResponse + Clone + Send + 'static,
B: Send + 'static,
{
type Future = std::future::Ready<Response>;
fn call(self, _req: Request<B>, _state: S) -> Self::Future {
std::future::ready(self.into_response())
}
}
/// A [`Service`] created from a [`Handler`] by applying a Tower middleware.
///
/// Created with [`Handler::layer`]. See that method for more details.
pub struct Layered<L, H, T, S, B, B2> {
layer: L,
handler: H,
_marker: PhantomData<fn() -> (T, S, B, B2)>,
}
impl<L, H, T, S, B, B2> fmt::Debug for Layered<L, H, T, S, B, B2>
where
L: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Layered")
.field("layer", &self.layer)
.finish()
}
}
impl<L, H, T, S, B, B2> Clone for Layered<L, H, T, S, B, B2>
where
L: Clone,
H: Clone,
{
fn clone(&self) -> Self {
Self {
layer: self.layer.clone(),
handler: self.handler.clone(),
_marker: PhantomData,
}
}
}
impl<H, S, T, L, B, B2> Handler<T, S, B2> for Layered<L, H, T, S, B, B2>
where
L: Layer<HandlerService<H, T, S, B>> + Clone + Send + 'static,
H: Handler<T, S, B>,
L::Service: Service<Request<B2>, Error = Infallible> + Clone + Send + 'static,
<L::Service as Service<Request<B2>>>::Response: IntoResponse,
<L::Service as Service<Request<B2>>>::Future: Send,
T: 'static,
S: 'static,
B: Send + 'static,
B2: Send + 'static,
{
type Future = future::LayeredFuture<B2, L::Service>;
fn call(self, req: Request<B2>, state: S) -> Self::Future {
use futures_util::future::{FutureExt, Map};
let svc = self.handler.with_state(state);
let svc = self.layer.layer(svc);
let future: Map<
_,
fn(
Result<
<L::Service as Service<Request<B2>>>::Response,
<L::Service as Service<Request<B2>>>::Error,
>,
) -> _,
> = svc.oneshot(req).map(|result| match result {
Ok(res) => res.into_response(),
Err(err) => match err {},
});
future::LayeredFuture::new(future)
}
}
/// Extension trait for [`Handler`]s that don't have state.
///
/// This provides convenience methods to convert the [`Handler`] into a [`Service`] or [`MakeService`].
///
/// [`MakeService`]: tower::make::MakeService
pub trait HandlerWithoutStateExt<T, B>: Handler<T, (), B> {
/// Convert the handler into a [`Service`] and no state.
fn into_service(self) -> HandlerService<Self, T, (), B>;
/// Convert the handler into a [`MakeService`] and no state.
///
/// See [`HandlerService::into_make_service`] for more details.
///
/// [`MakeService`]: tower::make::MakeService
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>>;
/// Convert the handler into a [`MakeService`] which stores information
/// about the incoming connection and has no state.
///
/// See [`HandlerService::into_make_service_with_connect_info`] for more details.
///
/// [`MakeService`]: tower::make::MakeService
#[cfg(feature = "tokio")]
fn into_make_service_with_connect_info<C>(
self,
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C>;
}
impl<H, T, B> HandlerWithoutStateExt<T, B> for H
where
H: Handler<T, (), B>,
{
fn into_service(self) -> HandlerService<Self, T, (), B> {
self.with_state(())
}
fn into_make_service(self) -> IntoMakeService<HandlerService<Self, T, (), B>> {
self.into_service().into_make_service()
}
#[cfg(feature = "tokio")]
fn into_make_service_with_connect_info<C>(
self,
) -> IntoMakeServiceWithConnectInfo<HandlerService<Self, T, (), B>, C> {
self.into_service().into_make_service_with_connect_info()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{body, extract::State, test_helpers::*};
use http::StatusCode;
use std::time::Duration;
use tower_http::{
compression::CompressionLayer, limit::RequestBodyLimitLayer,
map_request_body::MapRequestBodyLayer, map_response_body::MapResponseBodyLayer,
timeout::TimeoutLayer,
};
#[crate::test]
async fn handler_into_service() {
async fn handle(body: String) -> impl IntoResponse {
format!("you said: {body}")
}
let client = TestClient::new(handle.into_service());
let res = client.post("/").body("hi there!").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await, "you said: hi there!");
}
#[crate::test]
async fn with_layer_that_changes_request_body_and_state() {
async fn handle(State(state): State<&'static str>) -> &'static str {
state
}
let svc = handle
.layer((
RequestBodyLimitLayer::new(1024),
TimeoutLayer::new(Duration::from_secs(10)),
MapResponseBodyLayer::new(body::boxed),
CompressionLayer::new(),
))
.layer(MapRequestBodyLayer::new(body::boxed))
.with_state("foo");
let client = TestClient::new(svc);
let res = client.get("/").send().await;
assert_eq!(res.text().await, "foo");
}
}