Welcome to the new Golem Cloud Docs! 👋

Go

TinyGo (opens in a new tab) can compile Go code into core WASM modules and has limited support to WASI. Support for TinyGo-generated WASM files is limited in Golem right now but it can work in some cases.

Install it on OSX via brew:

brew tap tinygo-org/tools
brew install tinygo

You also have to install everything as described in Common tooling.

The easiest way to get started once the tooling is installed is to use the golem new command as described in the Quickstart.

If you prefer to do it from scratch, first we have to create a now Go module:

go mod init golem.com/tinygo_example

Then create a wit directory with a main.wit describing your component, optionally importing WASI or Golem specific extra interfaces (put them in wit/deps, copied from golem-cli's package):

package my:component;
 
world tinygo-example {
    import wasi:poll/poll;
    import wasi:io/streams;
    import wasi:http/types;
    import wasi:http/outgoing-handler;
 
    export example1: func(s: string) -> s32;
}

The next step is generating bindings with wit-bindgen:

wit-bindgen tiny-go --out-dir tinygo_example ./wit

And write your component in the module's main package (main.go in the root):

package main
 
import (
	"fmt"
	"math/rand"
	"time"
 
	"golem.com/tinygo_example/tinygo_example"
)
 
func init() {
	a := TinygoExampleImpl{}
	tinygo_example.SetTinygoExample(a)
}
 
type TinygoExampleImpl struct {
}
 
func (e TinygoExampleImpl) Example1(s string) int32 {
	fmt.Println(s)
 
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)
	v1 := r1.Int31()
	currentTime := time.Now()
 
	fmt.Println("test", currentTime.Year(), v1)
	return v1
}
 
func main() {
}

It's important to have an (empty) main function as well.

Finally compile the go source to a core WASM module:

tinygo build -target=wasi -tags=purego -o main.wasm main.go

The resulting WASM file in main.wasm is just a WASM module, not ready to be used with Golem.

First we need to embed the WIT interface definition with wasm-tools:

wasm-tools component embed ./wit main.wasm --output main.embed.wasm

The resulting WASM is still not a WASM component, but it has the binary encoding of the WIT file in a custom section.

The final step is converting the module in a WASM component, including mapping its WASI Preview1 imports into WASI Preview2 imports.

This is done with wasm-tools too:

wasm-tools component new main.embed.wasm -o component.wasm --adapt adapters/tier1/wasi_snapshot_preview1.wasm

The wasi_snapshot_preview1.wasm describes the mapping from WASI Preview1 to Preview2. You must use the version of this file packaged together with golem-cli.

💡

Make sure you use the tier1 adapter from the golem package!

The resulting component.wasm is ready to be used with Golem.

HTTP

We provide a Go package (opens in a new tab) for integration Go's http package with the WASI-HTTP interface provided by Golem.

To use this, first add the package to your module by

go get github.com/zivergetech/go-wasi-http@main

Then import and set the RoundTrip implementation provided by this package:

import (
	"net/http"
	go_wasi_http "github.com/zivergetech/go-wasi-http/roundtrip"
)
 
// ...
 
http.DefaultClient.Transport = go_wasi_http.WasiHttpTransport{}

Then use the http package or any other libraries built on top of that to communicate with external services:

postBody, _ := json.Marshal(ExampleRequest{
		Name:     "Something",
		Amount:   42,
		Comments: []string{"Hello", "World"},
	})
resp, err := http.Post("http://localhost:9999/post-example", "application/json", bytes.NewBuffer(postBody))
if err != nil {
	return fmt.Sprintln(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
	return fmt.Sprintln(err)
}
 
var response ExampleResponse
err = json.Unmarshal(body, &response)
if err != nil {
	return fmt.Sprintln(err)
}