Rust’s HTTP crates

2024-05-31

I’ve done HTTP stuff with Rust a few times, but far enough apart that I forget which crate is which. Here’s my notes, for future reference.

The tokio stack

These are the crates that build up the stack recommended at https://tokio.rs.

%3 axum axum hyper_util hyper_util axum->hyper_util tower_http tower_http axum->tower_http http http hyper hyper hyper->http hyper_util->hyper tower tower hyper_util->tower reqwest reqwest reqwest->hyper tower_service tower_service reqwest->tower_service tower->tower_service tower_http->http tower_http->tower warp warp warp->hyper warp->tower_service

http: Data types, no IO

Rust types for HTTP. Request, response, header, URI.

Doesn’t seem to cover serialization / deserialization (which would be different for HTTP/1,2,3) – just the API-level types. Kinda the Sans-IO approach, but even moreso.

1.0 release was published 2023-11-15.

hyper: Low level server/client

“Relatively low-level” server (and client) library. HTTP/2 support.

Server “serve[s] a single channel”, passing requests to a single Request -> Response function. It doesn’t deal with making the connection, or any details of that processing function, hence “low-level”.

tower: Network Middleware

Middleware ADT definitions, and some concrete implementations, for request/response things.

Two ADTs:

tower is not HTTP-specific; it doesn’t depend on any of the other libraries here. There’s a hyper-util that bridges Tower services to Hyper services. tower-http has some additional HTTP-specific middlewares; several other crates offer more middlewares.

axum: the tokio HTTP server

axum is designed to work with tokio and hyper. Runtime and transport layer independence is not a goal, at least for the time being.

Routes by path. Handlers take “extractors” as arguments, capturing e.g. a query parameter, URL segments, …and state, which feels weird to me but it seems like a common pattern.

From experience: feels highly polymorphic; stuff like extractors are vigorously overloaded.

@seanmonstar’s server and client

Sean McArthur is listed as the Hyperium project admin, which is the org that owns http and hyper. Unsurprisingly, these crates wrap hyper and use http types.

warp: Server library

Based on composition of filters; filters either reject a request, or produce a response. Compose filters combinator-style to create a routing table, URL/request/body extractors, … A filter can be turned into a tower::Service, and then further wrapped in Tower middleware.

Uses tokio::io types, but doesn’t require the runtime; smol-rs has an example of running warp in the smol runtime.

reqwest: Client library

Wrapping the hyper client. Async or blocking.

Interestingly, it uses tower-service to express readiness; Tower’s docs note the same middleware can be used in either a client or a server.

Server alternatives

actix-web

End-to-end server framework; routing, middleware, request/response…

Uses its own runtime, which instantiates a single-threaded tokio runtime per thread. No work-stealing.

Has its own actix_http crate, which is at least in part a re-export of http.

An interesting note in their docs:

Long ago, Actix Web was built on top of the actix actor framework. Now, Actix Web … is built using a different system. Though actix is still maintained, its usefulness as a general tool is diminishing as the futures and async/await ecosystem matures.

So, build to provide a green-threaded HTTP server before async/await was mature?

Rocket

Uses hyper and http under the hood. Uses a tokio runtime, though it seems they want the entry point to be via rocket::main.

Starting the server requires build, ignite, launch calls, “attaching fairings”… really leaning into the metaphor.

What about HTTP/3?

Doesn’t look like any of these have it yet. That’s a pity; seems like lots of servers do.

hyper HTTP/3 support is in the works; there’s a separate crate available that is “generic over a QUIC implementation”, just providing the HTTP/3 bindings. That “generic” does not cover quiche.

quiche is a QUIC and HTTP/3 implementation. Apparently this is the Actual Cloudflare Implementation, so it’d be bug-for-bug compatible with common clients. This does not use the http crate, so bridging between it and an h1/h2 service would Not Work Great.