Wasm Builders

Cover image for Fight complexity of WebAssembly with Reactr
Philippe Charrière
Philippe Charrière

Posted on • Updated on

Fight complexity of WebAssembly with Reactr

WASI (WebAssembly System Interface, an API) is the foundation to get wasm outside the JavaScript VM. Today several "WASI runtime" projects allow you to run wasm code from other languages (Rust, Go, C/C++, ...). The most recognised currently are:

From my perspective, when you want to free Wasm from the browser with WASI, WebAssembly brings two main "curses".

The first one is the type system.

WebAssembly has a too simple type system: only four numeric types, integers (32 and 64 bit) and floats (32 and 64 bit). It means, for example, that you cannot simply pass a string as a parameter of an imported function of the Wasm module.

We have pointers for that, and there is an excellent documentation on how to do that with WasmEdge: Pass complex parameters to Wasm functions

And in the near (I hope) future, we will gain the interface types (a new set of types that describes high-level values like strings, records, etc.).

The second one is more understandable because of the security: the wasm modules are executed in a sandboxed environment separated from the host (no access to the operating system) and other wasm modules. It means, for example, that you cannot even make an HTTP request from your Wasm module.
Thanks to WASI and the existing "WASI runtime" projects, we can solve this with the host functions; these are exported functions (of the host) to the Wasm module (as imported functions).

Once again, the WasmEdge project gives a clear explanation and a source code example: Host Functions

I’m more of a JavaScript programmer, and even if I’m starting to found in love with GoLang and RustLang, I don’t like doing complex acrobatics with pointers and memory.

But, there is Reactr

When starting my Wasm and GoLang journey this summer, I had a quick Twitter DM Chat with Connor Hicks and then discovered Atmo and Sat from Suborbital.

My quick definition of Atmo and Sat would be: the first one helps you create wasm-based web applications, the second one allows you to generate wasm microservices in a very straightforward manner.

Atmo and Sat are propulsed by the Reactr project. Reactr is a layer to facilitate the development of GoLang Wasm hosts (on the top of WasmEdge, Wasmer and Wastime) and Wasm modules. From a Reactr perspective, you can call the Wasm module a Runnable. Atmo and Sat allow to serve the Wasm modules (the Runnables) as http services.

To summarise, Reactr helps to expose host functions with ready to use helpers for using Redis, PostgreSQL, HTTP requests, etc. I would say that Reactr gives superpowers to the WASI host.

👋 PAY ATTENTION: Reactr is not only a Runnable SDK (have a look to the documentation)

My first Runnable: I want to pass a String to a Wasm function

A Runnable is a kind of function written in Go (with TinyGo compiler), Rust, Swift or Grain (and even in JavaScript or TypeScript! Stay tuned for a next episode). The easiest way to create a Runnable is the Suborbital CLI. If you’re a Mac or Linux user, the CLI is very easy to install:

brew tap suborbital/subo
brew install subo
Enter fullscreen mode Exit fullscreen mode

To create your first Go Runnable, type the following command:

subo create runnable hello-world --lang tinygo
Enter fullscreen mode Exit fullscreen mode

The subo CLI will generate the project structure of the Runnable with a starter source code:

Image Runnable in GitPod

To build the Runnable, use the below command:

subo build hello-world/
Enter fullscreen mode Exit fullscreen mode

This command will load the Suborbital toolchain and then build the hello-world wasm module. So, you will obtain a new file: hello-world.wasm.

Since now, we need another program to test the wasm module. We will develop a “Runnable launcher” with GoLang and Reactr.

GoLang “Launcher”

The source code of the “wasm launcher” is pretty straightforward:

Get a Reactr runtime instance
Load the wasm module and register the function
Call the function with this parameter: []byte("Bob Morane!")

package main

import (
    "fmt"
    "github.com/suborbital/reactr/rt"
    "github.com/suborbital/reactr/rwasm"
)

func main() {
    r := rt.New()
    doHelloWasm := r.Register("hello-world", rwasm.NewRunner("./hello-world/hello-world.wasm"))

    result, err := doHelloWasm("Bob Morane!").Then()
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(result.([]byte)))

}
Enter fullscreen mode Exit fullscreen mode

Run the launcher with the following command: go run main (or go build, and then call the executable).
You should get Hello Bob Morane!

From my JavaScript developer perspective, at the end it’s not so hard to pass a string to a wasm module. But now, it’s time to go further, I want to call an external http service from the wasm module.

My first Runnable: I want to call an http service from a Wasm function

Hopefully, Reactr exposes useful host functions to the Runnables (and for every supported language), like http requests, cache and many others: https://github.com/suborbital/reactr/tree/main/api/tinygo/runnable

So, let’s use the http API and update the source code of the Hello World Runnable like that:

package main

import (
    "log"

    "github.com/suborbital/reactr/api/tinygo/runnable"
    reactrHttp "github.com/suborbital/reactr/api/tinygo/runnable/http"
)

type HelloWorld struct{}

func (h HelloWorld) Run(input []byte) ([]byte, error) {
        // call an external web service
    payload, _ := reactrHttp.GET("https://jsonplaceholder.typicode.com/todos/1", nil)

        // display the service response
        log.Println(string(payload))

    return []byte("Hello, " + string(input)), nil
}

// initialize runnable, do not edit //
func main() {
    runnable.Use(HelloWorld{})
}


Enter fullscreen mode Exit fullscreen mode

https://jsonplaceholder.typicode.com/ is a very useful service to fake JSON API

Then, build the Runnable: subo build hello-world, and, run again the “Runnable launcher”, you should get something like this:

2022/03/26 07:02:34 {
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}
Hello, Bob Morane!
Enter fullscreen mode Exit fullscreen mode

🎉 Easy and almost Magic ✨

That’s all for today. Reactr is an incredible SDK to ease the life of developers when they are creating WebAssembly applications.

Next time, I would like to show you how to develop Wasm Micro Services with Reactr and Vektor. Stay tuned 😃.

Get the related source code of this post https://gitlab.com/k33g_org/wasm.builders/play-with-runnables

Discussion (0)