Skip to main content

wstd_axum/
lib.rs

1//! Support for the [`axum`] web server framework in wasi-http components, via
2//! [`wstd`].
3//!
4//! This crate is a pretty thin wrapper on [`wstd`] that allows users to
5//! use the [`axum`] crate on top of wstd's http support. This means that
6//! axum services can run anywhere the [wasi-http proxy world] is supported,
7//! e.g. in [`wasmtime serve`].
8//!
9//! Users of this crate should depend on `axum` with `default-features =
10//! false`, and opt in to any features that they require (e.g. form, json,
11//! matched-path, original-uri, query, tower-log, tracing). The axum crate
12//! features that require `hyper` or `tokio` are NOT supported (e.g. http1,
13//! http2, ws), because unlike in native applications, wasi-http components
14//! have an http implementation provided as imported interfaces (i.e.
15//! implemented the Wasm host), and do not use raw sockets inside of this
16//! program.
17//!
18//! # Examples
19//!
20//! The simplest use is via the `wstd_axum::http_server` proc macro.
21//! This macro can be applied to a sync or `async` `fn main` which returns
22//! an impl of the `tower_service::Service` trait, typically an
23//! `axum::Router`:
24//!
25//! ```rust,no_run
26#![doc = include_str!("../examples/hello_world.rs")]
27//! ```
28//!
29//! If users desire, they can instead use a `wstd::http_server` entry point
30//! and then use `wstd_axum::serve` directly. The following is equivelant
31//! to the above example:
32//!
33//! ```rust,no_run
34#![doc = include_str!("../examples/hello_world_nomacro.rs")]
35//! ```
36//!
37//! [`axum`]: https://docs.rs/axum/latest/axum/
38//! [`wstd`]: https://docs.rs/wstd/latest/wstd/
39//! [wasi-http proxy world]: https://github.com/WebAssembly/wasi-http
40//! [`wasmtime serve`]: https://wasmtime.dev/
41
42use axum::extract::Request;
43use axum::response::Response;
44use std::convert::Infallible;
45use tower_service::Service;
46
47pub use wstd_axum_macro::attr_macro_http_server as http_server;
48
49pub async fn serve<S>(
50    request: wstd::http::Request<wstd::http::Body>,
51    mut service: S,
52) -> wstd::http::error::Result<wstd::http::Response<wstd::http::Body>>
53where
54    S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
55    S::Future: Send,
56{
57    let resp = service
58        .call(
59            request.map(|incoming: wstd::http::Body| -> axum::body::Body {
60                axum::body::Body::new(incoming.into_boxed_body())
61            }),
62        )
63        .await
64        .unwrap_or_else(|err| match err {});
65    Ok(resp.map(|body: axum::body::Body| -> wstd::http::Body {
66        wstd::http::Body::from_http_body(body)
67    }))
68}