//! axum is a web application framework that focuses on ergonomics and modularity. //! //! # Table of contents //! //! - [High level features](#high-level-features) //! - [Compatibility](#compatibility) //! - [Handlers](#handlers) //! - [Routing](#routing) //! - [Precedence](#precedence) //! - [Matching multiple methods](#matching-multiple-methods) //! - [Extractors](#extractors) //! - [Building responses](#building-responses) //! - [Applying middleware](#applying-middleware) //! - [To individual handlers](#to-individual-handlers) //! - [To groups of routes](#to-groups-of-routes) //! - [Error handling](#error-handling) //! - [Sharing state with handlers](#sharing-state-with-handlers) //! - [Routing to any `Service`](#routing-to-any-service) //! - [Nesting applications](#nesting-applications) //! - [Required dependencies](#required-dependencies) //! - [Examples](#examples) //! - [Feature flags](#feature-flags) //! //! # High level features //! //! - Route requests to handlers with a macro free API. //! - Declaratively parse requests using extractors. //! - Simple and predictable error handling model. //! - Generate responses with minimal boilerplate. //! - Take full advantage of the [`tower`] and [`tower-http`] ecosystem of //! middleware, services, and utilities. //! //! In particular the last point is what sets `axum` apart from other frameworks. //! `axum` doesn't have its own middleware system but instead uses //! [`tower::Service`]. This means `axum` gets timeouts, tracing, compression, //! authorization, and more, for free. It also enables you to share middleware with //! applications written using [`hyper`] or [`tonic`]. //! //! # Compatibility //! //! axum is designed to work with [tokio] and [hyper]. Runtime and //! transport layer independence is not a goal, at least for the time being. //! //! # Example //! //! The "Hello, World!" of axum is: //! //! ```rust,no_run //! use axum::prelude::*; //! //! #[tokio::main] //! async fn main() { //! // build our application with a single route //! let app = route("/", get(|| async { "Hello, World!" })); //! //! // run it with hyper on localhost:3000 //! axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) //! .serve(app.into_make_service()) //! .await //! .unwrap(); //! } //! ``` //! //! # Handlers //! //! In axum a "handler" is an async function that accepts zero or more //! ["extractors"](#extractors) as arguments and returns something that //! can be converted [into a response](#building-responses). //! //! Handlers is where your custom domain logic lives and axum applications are //! built by routing between handlers. //! //! Some examples of handlers: //! //! ```rust //! use axum::prelude::*; //! use bytes::Bytes; //! use 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. //! async fn echo(body: Bytes) -> Result { //! if let Ok(string) = String::from_utf8(body.to_vec()) { //! Ok(string) //! } else { //! Err(StatusCode::BAD_REQUEST) //! } //! } //! ``` //! //! # Routing //! //! Routing between handlers looks like this: //! //! ```rust,no_run //! use axum::prelude::*; //! //! let app = route("/", get(get_slash).post(post_slash)) //! .route("/foo", get(get_foo)); //! //! async fn get_slash() { //! // `GET /` called //! } //! //! async fn post_slash() { //! // `POST /` called //! } //! //! async fn get_foo() { //! // `GET /foo` called //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! Routes can also be dynamic like `/users/:id`. See [extractors](#extractors) //! for more details. //! //! ## Precedence //! //! Note that routes are matched _bottom to top_ so routes that should have //! higher precedence should be added _after_ routes with lower precedence: //! //! ```rust //! use axum::{prelude::*, body::BoxBody}; //! use tower::{Service, ServiceExt, BoxError}; //! use http::{Method, Response, StatusCode}; //! use std::convert::Infallible; //! //! # #[tokio::main] //! # async fn main() { //! // `/foo` also matches `/:key` so adding the routes in this order means `/foo` //! // will be inaccessible. //! let mut app = route("/foo", get(|| async { "/foo called" })) //! .route("/:key", get(|| async { "/:key called" })); //! //! // Even though we use `/foo` as the request URI, `/:key` takes precedence //! // since its defined last. //! let (status, body) = call_service(&mut app, Method::GET, "/foo").await; //! assert_eq!(status, StatusCode::OK); //! assert_eq!(body, "/:key called"); //! //! // We have to add `/foo` after `/:key` since routes are matched bottom to //! // top. //! let mut new_app = route("/:key", get(|| async { "/:key called" })) //! .route("/foo", get(|| async { "/foo called" })); //! //! // Now it works //! let (status, body) = call_service(&mut new_app, Method::GET, "/foo").await; //! assert_eq!(status, StatusCode::OK); //! assert_eq!(body, "/foo called"); //! //! // And the other route works as well //! let (status, body) = call_service(&mut new_app, Method::GET, "/bar").await; //! assert_eq!(status, StatusCode::OK); //! assert_eq!(body, "/:key called"); //! //! // Little helper function to make calling a service easier. Just for //! // demonstration purposes. //! async fn call_service( //! svc: &mut S, //! method: Method, //! uri: &str, //! ) -> (StatusCode, String) //! where //! S: Service, Response = Response, Error = Infallible> //! { //! let req = Request::builder().method(method).uri(uri).body(Body::empty()).unwrap(); //! let res = svc.ready().await.unwrap().call(req).await.unwrap(); //! //! let status = res.status(); //! //! let body = res.into_body(); //! let body = hyper::body::to_bytes(body).await.unwrap(); //! let body = String::from_utf8(body.to_vec()).unwrap(); //! //! (status, body) //! } //! # } //! ``` //! //! ## Matching multiple methods //! //! If you want a path to accept multiple HTTP methods you must add them all at //! once: //! //! ```rust,no_run //! use axum::prelude::*; //! //! // `GET /` and `POST /` are both accepted //! let app = route("/", get(handler).post(handler)); //! //! // This will _not_ work. Only `POST /` will be accessible. //! let wont_work = route("/", get(handler)).route("/", post(handler)); //! //! async fn handler() {} //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # axum::Server::bind(&"".parse().unwrap()).serve(wont_work.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Extractors //! //! An extractor is a type that implements [`FromRequest`]. Extractors is how //! you pick apart the incoming request to get the parts your handler needs. //! //! For example, [`extract::Json`] is an extractor that consumes the request //! body and deserializes it as JSON into some target type: //! //! ```rust,no_run //! use axum::prelude::*; //! use serde::Deserialize; //! //! let app = route("/users", post(create_user)); //! //! #[derive(Deserialize)] //! struct CreateUser { //! email: String, //! password: String, //! } //! //! async fn create_user(payload: extract::Json) { //! let payload: CreateUser = payload.0; //! //! // ... //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! [`extract::Path`] can be used to extract params from a dynamic URL. It //! is compatible with any type that implements [`serde::Deserialize`], such as //! [`Uuid`]: //! //! ```rust,no_run //! use axum::prelude::*; //! use uuid::Uuid; //! //! let app = route("/users/:id", post(create_user)); //! //! async fn create_user(extract::Path(user_id): extract::Path) { //! // ... //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! You can also apply multiple extractors: //! //! ```rust,no_run //! use axum::prelude::*; //! use uuid::Uuid; //! use serde::Deserialize; //! //! let app = route("/users/:id/things", get(get_user_things)); //! //! #[derive(Deserialize)] //! struct Pagination { //! page: usize, //! per_page: usize, //! } //! //! impl Default for Pagination { //! fn default() -> Self { //! Self { page: 1, per_page: 30 } //! } //! } //! //! async fn get_user_things( //! extract::Path(user_id): extract::Path, //! pagination: Option>, //! ) { //! let pagination: Pagination = pagination.unwrap_or_default().0; //! //! // ... //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! Additionally `Request` is itself an extractor: //! //! ```rust,no_run //! use axum::prelude::*; //! //! let app = route("/users/:id", post(handler)); //! //! async fn handler(req: Request) { //! // ... //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! However it cannot be combined with other extractors since it consumes the //! entire request. //! //! See the [`extract`] module for more details. //! //! [`Uuid`]: https://docs.rs/uuid/latest/uuid/ //! [`FromRequest`]: crate::extract::FromRequest //! //! # Building responses //! //! Anything that implements [`IntoResponse`](response::IntoResponse) can be //! returned from a handler: //! //! ```rust,no_run //! use axum::{body::Body, response::{Html, Json}, prelude::*}; //! use http::{StatusCode, Response, Uri}; //! use serde_json::{Value, json}; //! //! // We've already seen returning &'static str //! async fn plain_text() -> &'static str { //! "foo" //! } //! //! // String works too and will get a `text/plain` content-type //! async fn plain_text_string(uri: Uri) -> String { //! format!("Hi from {}", uri.path()) //! } //! //! // Bytes will get a `application/octet-stream` content-type //! async fn bytes() -> Vec { //! vec![1, 2, 3, 4] //! } //! //! // `()` gives an empty response //! async fn empty() {} //! //! // `StatusCode` gives an empty response with that status code //! async fn empty_with_status() -> StatusCode { //! StatusCode::NOT_FOUND //! } //! //! // A tuple of `StatusCode` and something that implements `IntoResponse` can //! // be used to override the status code //! async fn with_status() -> (StatusCode, &'static str) { //! (StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong") //! } //! //! // `Html` gives a content-type of `text/html` //! async fn html() -> Html<&'static str> { //! Html("

Hello, World!

") //! } //! //! // `Json` gives a content-type of `application/json` and works with any type //! // that implements `serde::Serialize` //! async fn json() -> Json { //! Json(json!({ "data": 42 })) //! } //! //! // `Result` where `T` and `E` implement `IntoResponse` is useful for //! // returning errors //! async fn result() -> Result<&'static str, StatusCode> { //! Ok("all good") //! } //! //! // `Response` gives full control //! async fn response() -> Response { //! Response::builder().body(Body::empty()).unwrap() //! } //! //! let app = route("/plain_text", get(plain_text)) //! .route("/plain_text_string", get(plain_text_string)) //! .route("/bytes", get(bytes)) //! .route("/empty", get(empty)) //! .route("/empty_with_status", get(empty_with_status)) //! .route("/with_status", get(with_status)) //! .route("/html", get(html)) //! .route("/json", get(json)) //! .route("/result", get(result)) //! .route("/response", get(response)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Applying middleware //! //! axum is designed to take full advantage of the tower and tower-http //! ecosystem of middleware: //! //! ## To individual handlers //! //! A middleware can be applied to a single handler like so: //! //! ```rust,no_run //! use axum::prelude::*; //! use tower::limit::ConcurrencyLimitLayer; //! //! let app = route( //! "/", //! get(handler.layer(ConcurrencyLimitLayer::new(100))), //! ); //! //! async fn handler() {} //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! ## To groups of routes //! //! Middleware can also be applied to a group of routes like so: //! //! ```rust,no_run //! use axum::prelude::*; //! use tower::limit::ConcurrencyLimitLayer; //! //! let app = route("/", get(get_slash)) //! .route("/foo", post(post_foo)) //! .layer(ConcurrencyLimitLayer::new(100)); //! //! async fn get_slash() {} //! //! async fn post_foo() {} //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! ## Error handling //! //! Handlers created from async functions must always produce a response, even //! when returning a `Result` the error type must implement //! [`IntoResponse`]. In practice this makes error handling very predictable and //! easier to reason about. //! //! However when applying middleware, or embedding other tower services, errors //! might happen. For example [`Timeout`] will return an error if the timeout //! elapses. By default these errors will be propagated all the way up to hyper //! where the connection will be closed. If that isn't desirable you can call //! [`handle_error`](handler::Layered::handle_error) to handle errors from //! adding a middleware to a handler: //! //! ```rust,no_run //! use axum::prelude::*; //! use tower::{ //! BoxError, timeout::{TimeoutLayer, error::Elapsed}, //! }; //! use std::{borrow::Cow, time::Duration, convert::Infallible}; //! use http::StatusCode; //! //! let app = route( //! "/", //! get(handle //! .layer(TimeoutLayer::new(Duration::from_secs(30))) //! // `Timeout` uses `BoxError` as the error type //! .handle_error(|error: BoxError| { //! // Check if the actual error type is `Elapsed` which //! // `Timeout` returns //! if error.is::() { //! return Ok::<_, Infallible>(( //! StatusCode::REQUEST_TIMEOUT, //! "Request took too long".into(), //! )); //! } //! //! // If we encounter some error we don't handle return a generic //! // error //! return Ok::<_, Infallible>(( //! StatusCode::INTERNAL_SERVER_ERROR, //! // `Cow` lets us return either `&str` or `String` //! Cow::from(format!("Unhandled internal error: {}", error)), //! )); //! })), //! ); //! //! async fn handle() {} //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! The closure passed to [`handle_error`](handler::Layered::handle_error) must //! return `Result` where `T` implements //! [`IntoResponse`](response::IntoResponse). //! //! See [`routing::Layered::handle_error`] for more details. //! //! ## Applying multiple middleware //! //! [`tower::ServiceBuilder`] can be used to combine multiple middleware: //! //! ```rust,no_run //! use axum::prelude::*; //! use tower::ServiceBuilder; //! use tower_http::compression::CompressionLayer; //! use std::{borrow::Cow, time::Duration}; //! //! let middleware_stack = ServiceBuilder::new() //! // Return an error after 30 seconds //! .timeout(Duration::from_secs(30)) //! // Shed load if we're receiving too many requests //! .load_shed() //! // Process at most 100 requests concurrently //! .concurrency_limit(100) //! // Compress response bodies //! .layer(CompressionLayer::new()) //! .into_inner(); //! //! let app = route("/", get(|_: Request| async { /* ... */ })) //! .layer(middleware_stack); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Sharing state with handlers //! //! It is common to share some state between handlers for example to share a //! pool of database connections or clients to other services. That can be done //! using the [`AddExtension`] middleware (applied with [`AddExtensionLayer`]) //! and the [`extract::Extension`] extractor: //! //! ```rust,no_run //! use axum::{AddExtensionLayer, prelude::*}; //! use std::sync::Arc; //! //! struct State { //! // ... //! } //! //! let shared_state = Arc::new(State { /* ... */ }); //! //! let app = route("/", get(handler)).layer(AddExtensionLayer::new(shared_state)); //! //! async fn handler( //! state: extract::Extension>, //! ) { //! let state: Arc = state.0; //! //! // ... //! } //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Routing to any [`Service`] //! //! axum also supports routing to general [`Service`]s: //! //! ```rust,no_run //! use axum::{service, prelude::*}; //! use tower_http::services::ServeFile; //! use http::Response; //! use std::convert::Infallible; //! use tower::{service_fn, BoxError}; //! //! let app = route( //! // Any request to `/` goes to a service //! "/", //! // Services who's response body is not `axum::body::BoxBody` //! // can be wrapped in `axum::service::any` (or one of the other routing filters) //! // to have the response body mapped //! service::any(service_fn(|_: Request| async { //! let res = Response::new(Body::from("Hi from `GET /`")); //! Ok(res) //! })) //! ).route( //! "/foo", //! // This service's response body is `axum::body::BoxBody` so //! // it can be routed to directly. //! service_fn(|req: Request| async move { //! let body = Body::from(format!("Hi from `{} /foo`", req.method())); //! let body = axum::body::box_body(body); //! let res = Response::new(body); //! Ok(res) //! }) //! ).route( //! // GET `/static/Cargo.toml` goes to a service from tower-http //! "/static/Cargo.toml", //! service::get(ServeFile::new("Cargo.toml")) //! ); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! Routing to arbitrary services in this way has complications for backpressure //! ([`Service::poll_ready`]). See the [`service`] module for more details. //! //! # Nesting applications //! //! Applications can be nested by calling [`nest`](routing::nest): //! //! ```rust,no_run //! use axum::{prelude::*, routing::BoxRoute, body::{Body, BoxBody}}; //! use tower_http::services::ServeFile; //! use http::Response; //! //! fn api_routes() -> BoxRoute { //! route("/users", get(|_: Request| async { /* ... */ })).boxed() //! } //! //! let app = route("/", get(|_: Request| async { /* ... */ })) //! .nest("/api", api_routes()); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Required dependencies //! //! To use axum there are a few dependencies you have pull in as well: //! //! ```toml //! [dependencies] //! axum = "" //! hyper = { version = "", features = ["full"] } //! tokio = { version = "", features = ["full"] } //! tower = "" //! ``` //! //! The `"full"` feature for hyper and tokio isn't strictly necessary but its //! the easiest way to get started. //! //! Note that [`axum::Server`] is re-exported by axum so if thats all you need //! then you don't have to explicitly depend on hyper. //! //! Tower isn't strictly necessary either but helpful for testing. See the //! testing example in the repo to learn more about testing axum apps. //! //! # Examples //! //! The axum repo contains [a number of examples][examples] that show how to put all the //! pieces together. //! //! # Feature flags //! //! axum uses a set of [feature flags] to reduce the amount of compiled and //! optional dependencies. //! //! The following optional features are available: //! //! - `ws`: Enables WebSockets support. //! - `headers`: Enables extracting typed headers via [`extract::TypedHeader`]. //! - `multipart`: Enables parsing `multipart/form-data` requests with [`extract::Multipart`]. //! //! [`tower`]: https://crates.io/crates/tower //! [`tower-http`]: https://crates.io/crates/tower-http //! [`tokio`]: http://crates.io/crates/tokio //! [`hyper`]: http://crates.io/crates/hyper //! [`tonic`]: http://crates.io/crates/tonic //! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html#the-features-section //! [`IntoResponse`]: crate::response::IntoResponse //! [`Timeout`]: tower::timeout::Timeout //! [examples]: https://github.com/tokio-rs/axum/tree/main/examples //! [`axum::Server`]: hyper::server::Server #![warn( clippy::all, clippy::dbg_macro, clippy::todo, clippy::empty_enum, clippy::enum_glob_use, clippy::mem_forget, clippy::unused_self, clippy::filter_map_next, clippy::needless_continue, clippy::needless_borrow, clippy::match_wildcard_for_single_variants, clippy::if_let_mutex, clippy::mismatched_target_os, clippy::await_holding_lock, clippy::match_on_vec_items, clippy::imprecise_flops, clippy::suboptimal_flops, clippy::lossy_float_literal, clippy::rest_pat_in_fully_bound_structs, clippy::fn_params_excessive_bools, clippy::exit, clippy::inefficient_to_string, clippy::linkedlist, clippy::macro_use_imports, clippy::option_option, clippy::verbose_file_reads, clippy::unnested_or_patterns, rust_2018_idioms, future_incompatible, nonstandard_style, missing_debug_implementations, missing_docs )] #![deny(unreachable_pub, private_in_public)] #![allow(elided_lifetimes_in_paths, clippy::type_complexity)] #![forbid(unsafe_code)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))] use self::body::Body; use http::Request; use routing::{EmptyRouter, Route}; use tower::Service; #[macro_use] pub(crate) mod macros; mod buffer; mod json; mod util; pub mod body; pub mod extract; pub mod handler; pub mod response; pub mod routing; pub mod service; pub mod sse; #[cfg(feature = "ws")] #[cfg_attr(docsrs, doc(cfg(feature = "ws")))] pub mod ws; #[cfg(test)] mod tests; pub use async_trait::async_trait; #[doc(no_inline)] pub use http; #[doc(no_inline)] pub use hyper::Server; pub use tower_http::add_extension::{AddExtension, AddExtensionLayer}; pub use crate::json::Json; pub mod prelude { //! Re-exports of important traits, types, and functions used with axum. Meant to be glob //! imported. pub use crate::body::Body; pub use crate::extract; pub use crate::handler::{ any, connect, delete, get, head, options, patch, post, put, trace, Handler, }; pub use crate::response; pub use crate::route; pub use crate::routing::RoutingDsl; pub use http::Request; } /// Create a route. /// /// `description` is a string of path segments separated by `/`. Each segment /// can be either concrete or a capture: /// /// - `/foo/bar/baz` will only match requests where the path is `/foo/bar/bar`. /// - `/:foo` will match any route with exactly one segment _and_ it will /// capture the first segment and store it at the key `foo`. /// /// `service` is the [`Service`] that should receive the request if the path /// matches `description`. /// /// # Examples /// /// ```rust /// use axum::prelude::*; /// # use std::convert::Infallible; /// # use http::Response; /// # let service = tower::service_fn(|_: Request| async { /// # Ok::, Infallible>(Response::new(Body::empty())) /// # }); /// /// route("/", service); /// route("/users", service); /// route("/users/:id", service); /// route("/api/:version/users/:id/action", service); /// ``` /// /// # Panics /// /// Panics if `description` doesn't start with `/`. pub fn route(description: &str, service: S) -> Route> where S: Service> + Clone, { use routing::RoutingDsl; routing::EmptyRouter::not_found().route(description, service) } mod sealed { #![allow(unreachable_pub, missing_docs)] pub trait Sealed {} }