Building a hello-world http app using TinyGo + wasip2

Rajat Jindal

Aug 13th 2024, 09:30AM

In this blog, we will walk through how to implement a simple http handler using WebAssembly and TinyGo.

This blog post has been updated on May 3rd to work with latest version of TinyGo (v0.37.0) and Wasmtime (v0.32.0).

Prerequisites

In the previous blog, we walked through how to implement a simple hello world app using WebAssembly and TinyGo. Now, we will extend the app to implement a http handler, and serve it using wasmtime.

To start, lets add github.com/rajatjindal/wasi-go-sdk as our dependency. This sdk provides an easy to use interface on top of wasi's generated bindings.

Note: This SDK will likely be deprecated in favor of spin-go-sdk once the support for wasip2 is merged.

go mod init
go get github.com/rajatjindal/wasi-go-sdk
go mod tidy

Now, we can modify our main.go to initialize a http-handler:

package main

import (
        "fmt"
        "net/http"

        "github.com/rajatjindal/wasi-go-sdk/pkg/wasihttp"
)

func init() {
        wasihttp.Handle(func(w http.ResponseWriter, r *http.Request) {
                w.Header().Add("x-wasi-rocks", "true")
                w.WriteHeader(http.StatusOK)
                fmt.Fprint(w, "Hello Wasi !!")
        })
}

func main() {}

and then build it using TinyGo:

tinygo build -target=wasip2 \
    --wit-package $(go list -mod=readonly -m -f '{{.Dir}}' github.com/rajatjindal/wasi-go-sdk)/wit \
    --wit-world sdk \
    -o main.wasm main.go

There are a few differences between the build commands we used in Hello World app, and this http-handler:

  • We explicitly provide argument --wit-world sdk. This is required because by default TinyGo targets the wit-world cli, which is useful for building cli applications. The sdk wit-world is defined here
  • We provide argument --wit-package with a weird looking string as value. That weird looking string actually is a subcommand to fetch the WIT files from the sdk repo. This is required for building components using TinyGo.

and now we are ready run it using wasmtime

> wasmtime serve -Scli main.wasm
Serving HTTP on http://0.0.0.0:8080/

We need to provide -Scli because we import wasi:cli/environment@0.2.0 in the SDK, and using this option, the wasmtime runtime is configured to link the implementation.

From a different terminal, run the curl:

curl -v http://0.0.0.0:8080/
*   Trying 0.0.0.0:8080...
* Connected to 0.0.0.0 (127.0.0.1) port 8080
> GET / HTTP/1.1
> Host: 0.0.0.0:8080
> User-Agent: curl/8.4.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< x-wasi-rocks: true
< transfer-encoding: chunked
< date: Tue, 13 Aug 2024 03:52:46 GMT
< 

Hello Wasi !!

Congratulations !! We just executed our first http handler using WebAssembly + TinyGo + Wasmtime.