Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blog: announcing axum 0.7.0 #733

Merged
merged 8 commits into from
Nov 27, 2023
184 changes: 184 additions & 0 deletions content/blog/2023-11-23-announcing-axum-0-7-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
date: "2023-11-23"
title: "Announcing axum 0.7.0"
description: "November 23, 2022"
---

Today, we're happy to announce [`axum`] version 0.7. `axum` is an ergonomic
and modular web framework built with [`tokio`], [`tower`], and [`hyper`].

This also includes new major versions of [`axum-core`], [`axum-extra`], and
[`axum-macros`].

## `hyper` 1.0 support

The headline feature of `axum` 0.7 is support for `hyper` 1.0. `hyper` is a
foundational library for much of the networking ecosystem in Rust and finally
having a stable API is a big milestone.

`hyper` 1.0 comes with a big shuffling of the APIs. The previous low level APIs
(found in [`hyper::server::conn`]) is what has been stabilized whereas the high
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
level APIs (such as [`hyper::Server`]) has been removed.
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

The plan is to add the high level APIs to a new crate called [`hyper-util`].
There we can build out the APIs without worrying too much about stability
guarantees and backwards compatibility. When something is ready for
stabilization it can be moved into `hyper`.
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

`hyper-util` is still in early stages of development and some things (like the
previous `Server` type) are still missing.

Because `hyper-util` is not stable we don't want it to be part of `axum`'s
public API. If you want to use something from `hyper-util` you have to depend
it directly.

`axum` 0.7 also requires [`tower-http`] 0.5.
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

## A new `axum::serve` function

`axum` 0.6 provided `axum::Server` which was an easy way to get started.
`axum::Server` was however just a re-export of `hyper::Server` which has been
removed from `hyper` 1.0.

There isn't yet a full replacement in `hyper-util` so `axum` now provides its
own `serve` function:

```rust
use axum::{
routing::get,
Router,
};
use tokio::net::TcpListener;

let app = Router::new().route("/", get(|| async { "Hello, World!" }));

let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
```

The purpose of `axum::serve` is provide a way to get started with `axum`
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
quickly and as such it does not support any configuration options whatsoever.
If you need configuration you have to use `hyper` and `hyper-util` directly. We
provide an example showing how to do that [here][hyper-serve-example].
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

## Our own `Body` type

The [`http-body`] crate is also now 1.0 and that comes with a similar API split
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
that `hyper` and `hyper-util` has. `http-body` now just provides the core APIs
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
and high level utilities has been moved to [`http-body-util`]. That includes
things like `Full`, `Empty`, and `UnsyncBoxBody`, which used to be re-exported by
`axum`.

For the same reason that `hyper-util` shouldn't be part of `axum`'s public API,
`http-body-util` shouldn't either.

As a replacement `axum` now provides its own body type found at `axum::body::Body`.
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

Its API is similar to what `hyper::Body` had:

```rust
use axum::body::Body;
use futures::TryStreamExt;
use http_body_util::BodyExt;

// Create an empty body (Body::default() does the same)
Body::empty();

// Create bodies from strings or buffers
Body::from("foobar");
Body::from(Vec::<u8>::from([1, 3, 3, 7]));

// Wrap another type that implements `http_body::Body`
Body::new(another_http_body);

// Convert a `Body` into a `Stream` of data frames
let mut stream = body.into_data_stream();
while let Some(chunk) = stream.try_next().await? {
// ...
}

// Collect the body into a `Bytes`. Uses `BodyExt::collect`
// This replaces the previous `hyper::body::to_bytes` function
let bytes = body.collect().await?.to_bytes();
```

## Fewer generics

`axum::Router` used to be generic over the request body type. That meant
applying middleware that changed the request body type would have knock on
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
effects throughout your routes:

```rust
// This would work just fine
Router::new()
.route(
"/",
get(|body: Request<Body>| async { ... })
);

// But adding `tower_http::limit::RequestBodyLimitLayer` would make
// things no longer compile
Router::new()
.route(
"/",
get(|body: Request<Body>| async { ... })
)
.layer(tower_http::limit::RequestBodyLimitLayer::new(1024));
```

The reason it doesn't work is that `RequestBodyLimitLayer` changes the request
body type so you have to extract `Request<http_body::Limited<Body>>` instead of
`Request<Body>`. This was very subtle and the source of some confusion.

However in axum 0.7 everything continues working as before, regardless of which
middleware you add:
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

```rust
Router::new()
.route(
"/",
// You always extract `Request<Body>` no which middleware
// you add
get(|body: Request<Body>| async { ... })
)
.layer(tower_http::limit::RequestBodyLimitLayer::new(1024));
```

There is also a convenient type alias of `Request` that uses `Body`:
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

```rust
use axum::extract::Request;

Router::new().route("/", get(|body: Request| async { ... }));
```

The request body type parameter has been removed from all of `axum`'s types and
traits including `FromRequest`, `MethodRouter`, `Next`, and more.

## See the changelog for more

I encourage you to read the [changelog] to see all the changes and for tips on
how to update from 0.6 to 0.7.
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved

Also, please ask questions in [Discord] or [file issues] if you have trouble
davidpdrsn marked this conversation as resolved.
Show resolved Hide resolved
updating or discover bugs.

<div style="text-align:right">&mdash; David Pedersen (<a href="https://twitter.com/davidpdrsn">@davidpdrsn</a>)</div>

[`axum`]: https://crates.io/crates/axum
[`tokio`]: https://crates.io/crates/tokio
[`tower`]: https://crates.io/crates/tower
[`hyper`]: https://crates.io/crates/hyper
[`hyper-util`]: https://crates.io/crates/hyper-util
[`http-body`]: https://crates.io/crates/http-body
[`http-body-util`]: https://crates.io/crates/http-body-util
[`tower-http`]: https://crates.io/crates/tower-http
[changelog]: https://github.com/tokio-rs/axum/blob/main/axum/CHANGELOG.md
[Discord]: https://discord.gg/tokio
[file issues]: https://github.com/tokio-rs/axum/issues
[`hyper::server::conn`]: https://docs.rs/hyper/0.14.27/hyper/server/conn/index.html
[`hyper::Server`]: https://docs.rs/hyper/0.14.27/hyper/server/struct.Server.html
[`axum-core`]: https://crates.io/crates/axum-core
[`axum-extra`]: https://crates.io/crates/axum-extra
[`axum-macros`]: https://crates.io/crates/axum-macros
[hyper-serve-example]: https://github.com/tokio-rs/axum/blob/main/examples/serve-with-hyper/src/main.rs