|
| 1 | +# Hello WASI HTTP! |
| 2 | + |
| 3 | +This is a simple tutorial to get started with WASI HTTP using the `wasmtime serve` command introduced in [Wasmtime] 18.0. |
| 4 | +It runs an HTTP server and forwards requests to a Wasm component via the [WASI HTTP] API. |
| 5 | + |
| 6 | +[Wasmtime]: https://wasmtime.dev |
| 7 | +[WASI HTTP]: https://github.com/WebAssembly/wasi-http/ |
| 8 | + |
| 9 | +The WASI HTTP API is now stable, and part of WASI 0.2. |
| 10 | + |
| 11 | +So without further ado... |
| 12 | + |
| 13 | +## Let's go! |
| 14 | + |
| 15 | +First, [install `cargo-component`](https://github.com/bytecodealliance/cargo-component#requirements) (version 0.13.2 or later). `cargo-component` is a tool for building Wasm components implemented in Rust. For more |
| 16 | +information on building Wasm components from different languages, check [here]! |
| 17 | + |
| 18 | +[here]: https://component-model.bytecodealliance.org/language-support.html |
| 19 | + |
| 20 | +With that, build the Wasm component from source in this repository: |
| 21 | +```sh |
| 22 | +$ cargo component build |
| 23 | + Compiling hello-wasi-http v0.0.0 (/home/wasm/hello-wasi-http) |
| 24 | + Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.01s |
| 25 | + Creating component target/wasm32-wasip1/debug/hello_wasi_http.wasm |
| 26 | +``` |
| 27 | + |
| 28 | +This builds a Wasm component at `target/wasm32-wasip1/debug/hello_wasi_http.wasm`. |
| 29 | + |
| 30 | +To run it, we'll need at least Wasmtime `18.0`. Installation instructions are on [wasmtime.dev]. For example, on Linux or macOS, use the command below: |
| 31 | + |
| 32 | +```sh |
| 33 | +$ curl https://wasmtime.dev/install.sh -sSf | bash |
| 34 | +``` |
| 35 | + |
| 36 | +[wasmtime.dev]: https://wasmtime.dev/ |
| 37 | + |
| 38 | +Then, run in your terminal: |
| 39 | +```sh |
| 40 | +$ cargo component serve |
| 41 | +``` |
| 42 | +This starts up an HTTP server that, by default, listens on `0.0.0.0:8080`. |
| 43 | + |
| 44 | +With that running, in another window, we can now make requests! |
| 45 | +```sh |
| 46 | +$ curl http://localhost:8080 |
| 47 | +Hello, wasi:http/proxy world! |
| 48 | +``` |
| 49 | + |
| 50 | +## Optimizing! |
| 51 | + |
| 52 | +The above uses a `debug` build. To make a component that runs faster, build with `cargo component build --release`. |
| 53 | + |
| 54 | +It's also worth making sure you have a release build of Wasmtime; if you installed it from the instructions above |
| 55 | +with wasmtime.dev, you're good. |
| 56 | + |
| 57 | +Wasmtime has several tuning options that can improve performance in different situations—pass `-O help` for a |
| 58 | +list. One that's especially useful here is `-O pooling-allocator`. |
| 59 | + |
| 60 | +## Notes |
| 61 | + |
| 62 | +`wasmtime serve` uses the [proxy] world, which is a specialized world just for accepting requests and producing |
| 63 | +responses. One interesting thing about the proxy world is that it doesn't have a filesystem or network API. If you add |
| 64 | +code to the example that tries to access files or network sockets, it won't be able to build, because those APIs are |
| 65 | +not available in this world. This allows proxy components to run in many different places, including specialized |
| 66 | +serverless environments which may not provide traditional filesystem and network access. |
| 67 | + |
| 68 | +But, what if you do want to have it serve some files? One option will be to use |
| 69 | +[WASI-Virt](https://github.com/bytecodealliance/WASI-Virt), which is a tool that can bundle a filesystem with a |
| 70 | +component. |
| 71 | + |
| 72 | +Another option is to use a custom `world`. The proxy world is meant to be able to run in many different environments, |
| 73 | +but if you know your environment, and you know it has a filesystem, you could create your own world, by including both |
| 74 | +the `"wasi:http/proxy"` and `"wasi:filesystem/types"` or any other APIs you want the Wasm to be able to access. This |
| 75 | +would require a custom embedding of Wasmtime, as it wouldn't run under plain `wasmtime serve`, so it's a little more |
| 76 | +work to set up. |
| 77 | + |
| 78 | +In the future, we expect to see standard `world`s emerge that combine WASI HTTP with many other APIs, such as |
| 79 | +[wasi-cloud-core]. |
| 80 | + |
| 81 | +If you're interested in tutorials for any of these options, please reach out and say hi! |
| 82 | + |
| 83 | +[proxy]: https://github.com/WebAssembly/wasi-http/blob/main/wit/proxy.wit |
| 84 | +[wasi-cloud-core]: https://github.com/WebAssembly/wasi-cloud-core |
| 85 | + |
| 86 | +## Creating this repo |
| 87 | + |
| 88 | +Here are my notes on how I created this repository, in case you're interested in recreating it. |
| 89 | + |
| 90 | +To create a new project, run: |
| 91 | + |
| 92 | +```sh |
| 93 | +$ cargo component new --proxy --lib hello-wasi-http |
| 94 | + Created binary (application) `hello-wasi-http` package |
| 95 | + Updated manifest of package `hello-wasi-http` |
| 96 | + Generated source file `src/main.rs` |
| 97 | +$ cd hello-wasi-http |
| 98 | +``` |
| 99 | + |
| 100 | +Copy the `wit` directory from your version of Wasmtime, to ensure that we're using the same version of the API that |
| 101 | +Wasmtime is built with (e.g., for Wasmtime 18.0.0: https://github.com/bytecodealliance/wasmtime/tree/release-18.0.0). |
| 102 | + |
| 103 | +Then, I manually trimmed the filesystem and sockets dependencies out. |
| 104 | + |
| 105 | +In the future, we'll have wit dependencies stored in a registry, which will make this all much easier. |
| 106 | + |
| 107 | +I derived `src/lib.rs` from Wasmtime's `crates/test-programs/src/bin/api_proxy.rs` contents on the `main` branch, |
| 108 | +adapted it to work with cargo component, in particular by adding: |
| 109 | + |
| 110 | +```rust |
| 111 | +cargo_component_bindings::generate!(); |
| 112 | +``` |
| 113 | + |
| 114 | +Then, I renamed the `T` type to `Component`, which the bindings expect. |
| 115 | + |
| 116 | +Finally, add dependencies: |
| 117 | +``` |
| 118 | +$ cargo component add --target --path wit/deps/clocks wasi:clocks |
| 119 | +$ cargo component add --target --path wit/deps/io wasi:io |
| 120 | +$ cargo component add --target --path wit/deps/random wasi:random |
| 121 | +$ cargo component add --target --path wit/deps/cli wasi:cli |
| 122 | +$ cargo component add --target --path wit/deps/logging wasi:logging |
| 123 | +``` |
| 124 | + |
| 125 | +These don't all actually get used in this tutorial, but they're currently needed because of some of the interfaces we |
| 126 | +copied in from the Wasmtime tree reference them. |
| 127 | + |
| 128 | +> TODO: I should also make a `api_proxy_streaming.rs` version to show streaming. |
0 commit comments