| #![cfg_attr(nightly_error_messages, feature(rustc_attrs))] |
| //! axum is a web application framework that focuses on ergonomics and modularity. |
| //! |
| //! # Table of contents |
| //! |
| //! - [High-level features](#high-level-features) |
| //! - [Compatibility](#compatibility) |
| //! - [Example](#example) |
| //! - [Routing](#routing) |
| //! - [Handlers](#handlers) |
| //! - [Extractors](#extractors) |
| //! - [Responses](#responses) |
| //! - [Error handling](#error-handling) |
| //! - [Middleware](#middleware) |
| //! - [Sharing state with handlers](#sharing-state-with-handlers) |
| //! - [Building integrations for axum](#building-integrations-for-axum) |
| //! - [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::{ |
| //! routing::get, |
| //! Router, |
| //! }; |
| //! |
| //! #[tokio::main] |
| //! async fn main() { |
| //! // build our application with a single route |
| //! let app = Router::new().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(); |
| //! } |
| //! ``` |
| //! |
| //! Note using `#[tokio::main]` requires you enable tokio's `macros` and `rt-multi-thread` features |
| //! or just `full` to enable all features (`cargo add tokio --features macros,rt-multi-thread`). |
| //! |
| //! # Routing |
| //! |
| //! [`Router`] is used to setup which paths goes to which services: |
| //! |
| //! ```rust |
| //! use axum::{Router, routing::get}; |
| //! |
| //! // our router |
| //! let app = Router::new() |
| //! .route("/", get(root)) |
| //! .route("/foo", get(get_foo).post(post_foo)) |
| //! .route("/foo/bar", get(foo_bar)); |
| //! |
| //! // which calls one of these handlers |
| //! async fn root() {} |
| //! async fn get_foo() {} |
| //! async fn post_foo() {} |
| //! async fn foo_bar() {} |
| //! # async { |
| //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); |
| //! # }; |
| //! ``` |
| //! |
| //! See [`Router`] for more details on routing. |
| //! |
| //! # Handlers |
| //! |
| #![doc = include_str!("docs/handlers_intro.md")] |
| //! |
| //! See [`handler`](crate::handler) for more details on handlers. |
| //! |
| //! # Extractors |
| //! |
| //! An extractor is a type that implements [`FromRequest`] or [`FromRequestParts`]. Extractors are |
| //! how you pick apart the incoming request to get the parts your handler needs. |
| //! |
| //! ```rust |
| //! use axum::extract::{Path, Query, Json}; |
| //! use std::collections::HashMap; |
| //! |
| //! // `Path` gives you the path parameters and deserializes them. |
| //! async fn path(Path(user_id): Path<u32>) {} |
| //! |
| //! // `Query` gives you the query parameters and deserializes them. |
| //! async fn query(Query(params): Query<HashMap<String, String>>) {} |
| //! |
| //! // Buffer the request body and deserialize it as JSON into a |
| //! // `serde_json::Value`. `Json` supports any type that implements |
| //! // `serde::Deserialize`. |
| //! async fn json(Json(payload): Json<serde_json::Value>) {} |
| //! ``` |
| //! |
| //! See [`extract`](crate::extract) for more details on extractors. |
| //! |
| //! # Responses |
| //! |
| //! Anything that implements [`IntoResponse`] can be returned from handlers. |
| //! |
| //! ```rust,no_run |
| //! use axum::{ |
| //! body::Body, |
| //! routing::get, |
| //! response::Json, |
| //! Router, |
| //! }; |
| //! use serde_json::{Value, json}; |
| //! |
| //! // `&'static str` becomes a `200 OK` with `content-type: text/plain; charset=utf-8` |
| //! async fn plain_text() -> &'static str { |
| //! "foo" |
| //! } |
| //! |
| //! // `Json` gives a content-type of `application/json` and works with any type |
| //! // that implements `serde::Serialize` |
| //! async fn json() -> Json<Value> { |
| //! Json(json!({ "data": 42 })) |
| //! } |
| //! |
| //! let app = Router::new() |
| //! .route("/plain_text", get(plain_text)) |
| //! .route("/json", get(json)); |
| //! # async { |
| //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); |
| //! # }; |
| //! ``` |
| //! |
| //! See [`response`](crate::response) for more details on building responses. |
| //! |
| //! # Error handling |
| //! |
| //! axum aims to have a simple and predictable error handling model. That means |
| //! it is simple to convert errors into responses and you are guaranteed that |
| //! all errors are handled. |
| //! |
| //! See [`error_handling`](crate::error_handling) for more details on axum's |
| //! error handling model and how to handle errors gracefully. |
| //! |
| //! # Middleware |
| //! |
| //! There are several different ways to write middleware for axum. See |
| //! [`middleware`](crate::middleware) for more details. |
| //! |
| //! # Sharing state with handlers |
| //! |
| //! It is common to share some state between handlers. For example, a |
| //! pool of database connections or clients to other services may need to |
| //! be shared. |
| //! |
| //! The three most common ways of doing that are: |
| //! - Using the [`State`] extractor |
| //! - Using request extensions |
| //! - Using closure captures |
| //! |
| //! ## Using the [`State`] extractor |
| //! |
| //! ```rust,no_run |
| //! use axum::{ |
| //! extract::State, |
| //! routing::get, |
| //! Router, |
| //! }; |
| //! use std::sync::Arc; |
| //! |
| //! struct AppState { |
| //! // ... |
| //! } |
| //! |
| //! let shared_state = Arc::new(AppState { /* ... */ }); |
| //! |
| //! let app = Router::new() |
| //! .route("/", get(handler)) |
| //! .with_state(shared_state); |
| //! |
| //! async fn handler( |
| //! State(state): State<Arc<AppState>>, |
| //! ) { |
| //! // ... |
| //! } |
| //! # async { |
| //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); |
| //! # }; |
| //! ``` |
| //! |
| //! You should prefer using [`State`] if possible since it's more type safe. The downside is that |
| //! it's less dynamic than request extensions. |
| //! |
| //! See [`State`] for more details about accessing state. |
| //! |
| //! ## Using request extensions |
| //! |
| //! Another way to extract state in handlers is using [`Extension`](crate::extract::Extension) as |
| //! layer and extractor: |
| //! |
| //! ```rust,no_run |
| //! use axum::{ |
| //! extract::Extension, |
| //! routing::get, |
| //! Router, |
| //! }; |
| //! use std::sync::Arc; |
| //! |
| //! struct AppState { |
| //! // ... |
| //! } |
| //! |
| //! let shared_state = Arc::new(AppState { /* ... */ }); |
| //! |
| //! let app = Router::new() |
| //! .route("/", get(handler)) |
| //! .layer(Extension(shared_state)); |
| //! |
| //! async fn handler( |
| //! Extension(state): Extension<Arc<AppState>>, |
| //! ) { |
| //! // ... |
| //! } |
| //! # async { |
| //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); |
| //! # }; |
| //! ``` |
| //! |
| //! The downside to this approach is that you'll get runtime errors |
| //! (specifically a `500 Internal Server Error` response) if you try and extract |
| //! an extension that doesn't exist, perhaps because you forgot to add the |
| //! middleware or because you're extracting the wrong type. |
| //! |
| //! ## Using closure captures |
| //! |
| //! State can also be passed directly to handlers using closure captures: |
| //! |
| //! ```rust,no_run |
| //! use axum::{ |
| //! Json, |
| //! extract::{Extension, Path}, |
| //! routing::{get, post}, |
| //! Router, |
| //! }; |
| //! use std::sync::Arc; |
| //! use serde::Deserialize; |
| //! |
| //! struct AppState { |
| //! // ... |
| //! } |
| //! |
| //! let shared_state = Arc::new(AppState { /* ... */ }); |
| //! |
| //! let app = Router::new() |
| //! .route( |
| //! "/users", |
| //! post({ |
| //! let shared_state = Arc::clone(&shared_state); |
| //! move |body| create_user(body, shared_state) |
| //! }), |
| //! ) |
| //! .route( |
| //! "/users/:id", |
| //! get({ |
| //! let shared_state = Arc::clone(&shared_state); |
| //! move |path| get_user(path, shared_state) |
| //! }), |
| //! ); |
| //! |
| //! async fn get_user(Path(user_id): Path<String>, state: Arc<AppState>) { |
| //! // ... |
| //! } |
| //! |
| //! async fn create_user(Json(payload): Json<CreateUserPayload>, state: Arc<AppState>) { |
| //! // ... |
| //! } |
| //! |
| //! #[derive(Deserialize)] |
| //! struct CreateUserPayload { |
| //! // ... |
| //! } |
| //! # async { |
| //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); |
| //! # }; |
| //! ``` |
| //! |
| //! The downside to this approach is that it's a little more verbose than using |
| //! [`State`] or extensions. |
| //! |
| //! # Building integrations for axum |
| //! |
| //! Libraries authors that want to provide [`FromRequest`], [`FromRequestParts`], or |
| //! [`IntoResponse`] implementations should depend on the [`axum-core`] crate, instead of `axum` if |
| //! possible. [`axum-core`] contains core types and traits and is less likely to receive breaking |
| //! changes. |
| //! |
| //! # Required dependencies |
| //! |
| //! To use axum there are a few dependencies you have to pull in as well: |
| //! |
| //! ```toml |
| //! [dependencies] |
| //! axum = "<latest-version>" |
| //! hyper = { version = "<latest-version>", features = ["full"] } |
| //! tokio = { version = "<latest-version>", features = ["full"] } |
| //! tower = "<latest-version>" |
| //! ``` |
| //! |
| //! The `"full"` feature for hyper and tokio isn't strictly necessary but it's |
| //! the easiest way to get started. |
| //! |
| //! Note that [`hyper::Server`] is re-exported by axum so if that's 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: |
| //! |
| //! Name | Description | Default? |
| //! ---|---|--- |
| //! `headers` | Enables extracting typed headers via [`TypedHeader`] | No |
| //! `http1` | Enables hyper's `http1` feature | Yes |
| //! `http2` | Enables hyper's `http2` feature | No |
| //! `json` | Enables the [`Json`] type and some similar convenience functionality | Yes |
| //! `macros` | Enables optional utility macros | No |
| //! `matched-path` | Enables capturing of every request's router path and the [`MatchedPath`] extractor | Yes |
| //! `multipart` | Enables parsing `multipart/form-data` requests with [`Multipart`] | No |
| //! `original-uri` | Enables capturing of every request's original URI and the [`OriginalUri`] extractor | Yes |
| //! `tokio` | Enables `tokio` as a dependency and `axum::Server`, `SSE` and `extract::connect_info` types. | Yes |
| //! `tower-log` | Enables `tower`'s `log` feature | Yes |
| //! `tracing` | Log rejections from built-in extractors | No |
| //! `ws` | Enables WebSockets support via [`extract::ws`] | No |
| //! `form` | Enables the `Form` extractor | Yes |
| //! `query` | Enables the `Query` extractor | Yes |
| //! |
| //! [`TypedHeader`]: crate::extract::TypedHeader |
| //! [`MatchedPath`]: crate::extract::MatchedPath |
| //! [`Multipart`]: crate::extract::Multipart |
| //! [`OriginalUri`]: crate::extract::OriginalUri |
| //! [`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 |
| //! [`Router::merge`]: crate::routing::Router::merge |
| //! [`axum::Server`]: hyper::server::Server |
| //! [`Service`]: tower::Service |
| //! [`Service::poll_ready`]: tower::Service::poll_ready |
| //! [`Service`'s]: tower::Service |
| //! [`tower::Service`]: tower::Service |
| //! [tower-guides]: https://github.com/tower-rs/tower/tree/master/guides |
| //! [`Uuid`]: https://docs.rs/uuid/latest/uuid/ |
| //! [`FromRequest`]: crate::extract::FromRequest |
| //! [`FromRequestParts`]: crate::extract::FromRequestParts |
| //! [`HeaderMap`]: http::header::HeaderMap |
| //! [`Request`]: http::Request |
| //! [customize-extractor-error]: https://github.com/tokio-rs/axum/blob/main/examples/customize-extractor-error/src/main.rs |
| //! [axum-macros]: https://docs.rs/axum-macros |
| //! [`debug_handler`]: https://docs.rs/axum-macros/latest/axum_macros/attr.debug_handler.html |
| //! [`Handler`]: crate::handler::Handler |
| //! [`Infallible`]: std::convert::Infallible |
| //! [load shed]: tower::load_shed |
| //! [`axum-core`]: http://crates.io/crates/axum-core |
| //! [`State`]: crate::extract::State |
| |
| #![warn( |
| clippy::all, |
| 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, |
| clippy::str_to_string, |
| 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_auto_cfg, doc_cfg))] |
| #![cfg_attr(test, allow(clippy::float_cmp))] |
| #![cfg_attr(not(test), warn(clippy::print_stdout, clippy::dbg_macro))] |
| |
| #[macro_use] |
| pub(crate) mod macros; |
| |
| mod boxed; |
| mod extension; |
| #[cfg(feature = "form")] |
| mod form; |
| #[cfg(feature = "json")] |
| mod json; |
| mod service_ext; |
| #[cfg(feature = "headers")] |
| mod typed_header; |
| mod util; |
| |
| pub mod body; |
| pub mod error_handling; |
| pub mod extract; |
| pub mod handler; |
| pub mod middleware; |
| pub mod response; |
| pub mod routing; |
| |
| #[cfg(test)] |
| mod test_helpers; |
| |
| #[doc(no_inline)] |
| pub use async_trait::async_trait; |
| #[cfg(feature = "headers")] |
| #[doc(no_inline)] |
| pub use headers; |
| #[doc(no_inline)] |
| pub use http; |
| #[cfg(feature = "tokio")] |
| #[doc(no_inline)] |
| pub use hyper::Server; |
| |
| #[doc(inline)] |
| pub use self::extension::Extension; |
| #[doc(inline)] |
| #[cfg(feature = "json")] |
| pub use self::json::Json; |
| #[doc(inline)] |
| pub use self::routing::Router; |
| |
| #[doc(inline)] |
| #[cfg(feature = "headers")] |
| pub use self::typed_header::TypedHeader; |
| |
| #[doc(inline)] |
| #[cfg(feature = "form")] |
| pub use self::form::Form; |
| |
| #[doc(inline)] |
| pub use axum_core::{BoxError, Error, RequestExt, RequestPartsExt}; |
| |
| #[cfg(feature = "macros")] |
| pub use axum_macros::debug_handler; |
| |
| pub use self::service_ext::ServiceExt; |
| |
| #[cfg(test)] |
| use axum_macros::__private_axum_test as test; |