Rust & Wasm: Create Server-Side Apps
Until now, we have created and deployed WASM modules in a browser, CLI and Python. In this article, we will instead create a web server completely in Rust, compile it to WASM and run it using WasmEdge.
Create a TCP Listener
Let’s first create a basic rust project
cargo new wasmedge-demo
and add hyper_wasi
(for http server) and tokio_wasi
(for async processors) in Cargo.toml like so:
[dependencies]
+hyper_wasi = { version = "0.15", features = ["full"]}
+tokio_wasi = { version = "1", features = ["rt", "macros", "net", "time", "io-util"]}
Next, let’s modify our lib.rs
to create an async main
that creates a TCP connection listener:
use std::net::SocketAddr;
use tokio::net::TcpListener;
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
let listener = TcpListener::bind(addr).await?;
println!("Listening on http://{}", addr);
Ok(())
}
This essentially creates a server on http://0.0.0.0
(or localhost) at port 8080.
Handle Connections
Now, let’s add the ability to handle new connections:
+use hyper::server::conn::Http;
+use hyper::service::service_fn;
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
let listener = TcpListener::bind(addr).await?;
println!("Listening on http://{}", addr);
+ loop {
+ let (stream, _) = listener.accept().await?;
+
+ tokio::task::spawn(async move {
+ if let Err(err) = Http::new().serve_connection(stream, service_fn(handle_req)).await { // `handle_req` will be defined later
+ println!("Error serving connection: {:?}", err);
+ }
+ });
+ }
-
- Ok(())
}
This essentially waits for a connection, launches a new thread to process the requests and loops to start to wait for another connection.
Process Requests
Now, let’s define our handle_req
function that handles any request to the given connection:
+use hyper::{Body, Request, Response};
+async fn handle_req(_req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
+ Ok(Response::new(Body::from(
+ "Hello World!",
+ )))
+}
This handler just responds with Hello World!
for any request to the server.
Launch Server
To launch our server, let’s first install WasmEdge:
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
Next, let’s build our app for wasm32-wasi
:
cargo build --target wasm32-wasi --release
Finally, let’s run our server:
wasmedge target/wasm32-wasi/release/wasmedge-demo.wasm
You should see Listening on http://0.0.0.0:8080
on the console.
Now, our server is ready to serve requests. You can open the link on the browser and see Hello World!
:)
If you liked this article, subscribe here to get the complete code and updates for the entire collection: