85731a4f1d
- Overall: - **fixed:** All known compile time issues are resolved, including those with `boxed` and those introduced by Rust 1.56 ([#404]) - **breaking:** The router's type is now always `Router` regardless of how many routes or middleware are applied ([#404]) This means router types are all always nameable: ```rust fn my_routes() -> Router { Router::new().route( "/users", post(|| async { "Hello, World!" }), ) } ``` - **breaking:** Added feature flags for HTTP1 and JSON. This enables removing a few dependencies if your app only uses HTTP2 or doesn't use JSON. Its only a breaking change if you depend on axum with `default_features = false`. ([#286]) - **breaking:** `Route::boxed` and `BoxRoute` have been removed as they're no longer necessary ([#404]) - **breaking:** `Nested`, `Or` types are now private. They no longer had to be public because `Router` is internally boxed ([#404]) - **breaking:** Remove `routing::Layered` as it didn't actually do anything and thus wasn't necessary - **breaking:** Vendor `AddExtensionLayer` and `AddExtension` to reduce public dependencies - **breaking:** `body::BoxBody` is now a type alias for `http_body::combinators::UnsyncBoxBody` and thus is no longer `Sync`. This is because bodies are streams and requiring streams to be `Sync` is unnecessary. - **added:** Implement `IntoResponse` for `http_body::combinators::UnsyncBoxBody`. - **added:** Add `Handler::into_make_service` for serving a handler without a `Router`. - **added:** Add `Handler::into_make_service_with_connect_info` for serving a handler without a `Router`, and storing info about the incoming connection. - **breaking:** axum's minimum support rust version is not 1.54 - Routing: - Big internal refactoring of routing leading to several improvements ([#363]) - **added:** Wildcard routes like `.route("/api/users/*rest", service)` are now supported. - **fixed:** The order routes are added in no longer matters. - **fixed:** Adding a conflicting route will now cause a panic instead of silently making a route unreachable. - **fixed:** Route matching is faster as number of routes increase. - **fixed:** Correctly handle trailing slashes in routes: - If a route with a trailing slash exists and a request without a trailing slash is received, axum will send a 301 redirection to the route with the trailing slash. - Or vice versa if a route without a trailing slash exists and a request with a trailing slash is received. - This can be overridden by explicitly defining two routes: One with and one without trailing a slash. - **breaking:** Method routing for handlers have been moved from `axum::handler` to `axum::routing`. So `axum::handler::get` now lives at `axum::routing::get` ([#405]) - **breaking:** Method routing for services have been moved from `axum::service` to `axum::routing`. So `axum::service::get` now lives at, etc. `axum::routing::service_method_routing::get`, etc. ([#405]) - **breaking:** `Router::or` renamed to `Router::merge` and will now panic on overlapping routes. It now only accepts `Router`s and not general `Service`s. Use `Router::fallback` for adding fallback routes ([#408]) - **added:** `Router::fallback` for adding handlers for request that didn't match any routes. `Router::fallback` must be use instead of `nest("/", _)` ([#408]) - **breaking:** `EmptyRouter` has been renamed to `MethodNotAllowed` as its only used in method routers and not in path routers (`Router`) - **breaking:** Remove support for routing based on the `CONNECT` method. An example of combining axum with and HTTP proxy can be found [here][proxy] ([#428]) - Extractors: - **fixed:** Expand accepted content types for JSON requests ([#378]) - **fixed:** Support deserializing `i128` and `u128` in `extract::Path` - **breaking:** Automatically do percent decoding in `extract::Path` ([#272]) - **breaking:** Change `Connected::connect_info` to return `Self` and remove the associated type `ConnectInfo` ([#396]) - **added:** Add `extract::MatchedPath` for accessing path in router that matched the request ([#412]) - Error handling: - **breaking:** Simplify error handling model ([#402]): - All services part of the router are now required to be infallible. - Error handling utilities have been moved to an `error_handling` module. - `Router::check_infallible` has been removed since routers are always infallible with the error handling changes. - Error handling closures must now handle all errors and thus always return something that implements `IntoResponse`. With these changes handling errors from fallible middleware is done like so: ```rust,no_run use axum::{ routing::get, http::StatusCode, error_handling::HandleErrorLayer, response::IntoResponse, Router, BoxError, }; use tower::ServiceBuilder; use std::time::Duration; let middleware_stack = ServiceBuilder::new() // Handle errors from middleware // // This middleware most be added above any fallible // ones if you're using `ServiceBuilder`, due to how ordering works .layer(HandleErrorLayer::new(handle_error)) // Return an error after 30 seconds .timeout(Duration::from_secs(30)); let app = Router::new() .route("/", get(|| async { /* ... */ })) .layer(middleware_stack); fn handle_error(_error: BoxError) -> impl IntoResponse { StatusCode::REQUEST_TIMEOUT } ``` And handling errors from fallible leaf services is done like so: ```rust use axum::{ Router, service, body::Body, routing::service_method_routing::get, response::IntoResponse, http::{Request, Response}, error_handling::HandleErrorExt, // for `.handle_error` }; use std::{io, convert::Infallible}; use tower::service_fn; let app = Router::new() .route( "/", get(service_fn(|_req: Request<Body>| async { let contents = tokio::fs::read_to_string("some_file").await?; Ok::<_, io::Error>(Response::new(Body::from(contents))) })) .handle_error(handle_io_error), ); fn handle_io_error(error: io::Error) -> impl IntoResponse { // ... } ``` - Misc: - `InvalidWebsocketVersionHeader` has been renamed to `InvalidWebSocketVersionHeader` ([#416]) - `WebsocketKeyHeaderMissing` has been renamed to `WebSocketKeyHeaderMissing` ([#416]) [#339]: https://github.com/tokio-rs/axum/pull/339 [#286]: https://github.com/tokio-rs/axum/pull/286 [#272]: https://github.com/tokio-rs/axum/pull/272 [#378]: https://github.com/tokio-rs/axum/pull/378 [#363]: https://github.com/tokio-rs/axum/pull/363 [#396]: https://github.com/tokio-rs/axum/pull/396 [#402]: https://github.com/tokio-rs/axum/pull/402 [#404]: https://github.com/tokio-rs/axum/pull/404 [#405]: https://github.com/tokio-rs/axum/pull/405 [#408]: https://github.com/tokio-rs/axum/pull/408 [#412]: https://github.com/tokio-rs/axum/pull/412 [#416]: https://github.com/tokio-rs/axum/pull/416 [#428]: https://github.com/tokio-rs/axum/pull/428 [proxy]: https://github.com/tokio-rs/axum/blob/main/examples/http-proxy/src/main.rs |
||
---|---|---|
.github | ||
examples | ||
src | ||
.clippy.toml | ||
.gitignore | ||
Cargo.toml | ||
CHANGELOG.md | ||
CONTRIBUTING.md | ||
deny.toml | ||
LICENSE | ||
README.md |
axum
axum
is a web application framework that focuses on ergonomics and modularity.
More information about this crate can be found in the crate documentation.
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
andtower-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
.
Usage example
Note this example uses main
which contains breaking changes. See the
v0.2.x branch for an example
using 0.2.
use axum::{
routing::{get, post},
http::StatusCode,
response::IntoResponse,
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
// initialize tracing
tracing_subscriber::fmt::init();
// build our application with a route
let app = Router::new()
// `GET /` goes to `root`
.route("/", get(root))
// `POST /users` goes to `create_user`
.route("/users", post(create_user));
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
tracing::debug!("listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
// basic handler that responds with a static string
async fn root() -> &'static str {
"Hello, World!"
}
async fn create_user(
// this argument tells axum to parse the request body
// as JSON into a `CreateUser` type
Json(payload): Json<CreateUser>,
) -> impl IntoResponse {
// insert your application logic here
let user = User {
id: 1337,
username: payload.username,
};
// this will be converted into a JSON response
// with a status code of `201 Created`
(StatusCode::CREATED, Json(user))
}
// the input to our `create_user` handler
#[derive(Deserialize)]
struct CreateUser {
username: String,
}
// the output to our `create_user` handler
#[derive(Serialize)]
struct User {
id: u64,
username: String,
}
See the crate documentation for way more examples.
Performance
axum
is a relatively thin layer on top of hyper
and adds very little
overhead. So axum
's performance is comparable to hyper
. You can find a
benchmark here.
Safety
This crate uses #![forbid(unsafe_code)]
to ensure everything is implemented in
100% safe Rust.
Minimum supported Rust version
axum 0.2's MSRV is 1.51. axum 0.3's (still work-in-progress) MSRV will be 1.54.
Examples
The examples folder contains various examples of how to use axum
. The
docs also have lots of examples
Getting Help
In the axum
's repo we also have a number of examples showing how
to put everything together. You're also welcome to ask in the Discord
channel or open an issue with your question.
Contributing
🎈 Thanks for your help improving the project! We are so happy to have
you! We have a contributing guide to help you get involved in the
axum
project.
License
This project is licensed under the MIT license.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in axum
by you, shall be licensed as MIT, without any
additional terms or conditions.