tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.49k stars 913 forks source link

Make a http request from wasi #4540

Open dshemin opened 1 month ago

dshemin commented 1 month ago

Hi!

I try to make a http request from WASM module running on wazero and got an error^

Netdev not set

I try to use netdev package but can't find any suitable examples. Can someone tell me is it possible or not?

My module:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "net/http"
    "os"
    "time"

    "tinygo.org/x/drivers/netdev"
)

//go:generate easyjson main.go

//export call
func call() {
    netdev.UseNetdev(/* That i should pass here? */)
    resp, err := http.Get("https://swapi.dev/api/people/1")
    handleErr(err, "get")

    if resp.StatusCode != http.StatusOK {
        handleErr(errors.New("not 200"), "check status code")
    }
    defer resp.Body.Close()

    var p People
    err = json.NewDecoder(resp.Body).Decode(&p)
    handleErr(err, "decode")

    fmt.Printf("%#v", p)
}

func handleErr(err error, msg string) {
    if err != nil {
        fmt.Println(msg + ": " + err.Error())
        os.Exit(1)
    }
}

//easyjson:json
type People struct {
    Name      string    `json:"name"`
    Height    string    `json:"height"`
    Mass      string    `json:"mass"`
    HairColor string    `json:"hair_color"`
    SkinColor string    `json:"skin_color"`
    EyeColor  string    `json:"eye_color"`
    BirthYear string    `json:"birth_year"`
    Gender    string    `json:"gender"`
    Homeworld string    `json:"homeworld"`
    Films     []string  `json:"films"`
    Species   []string  `json:"species"`
    Vehicles  []string  `json:"vehicles"`
    Starships []string  `json:"starships"`
    Created   time.Time `json:"created"`
    Edited    time.Time `json:"edited"`
    URL       string    `json:"url"`
}

func main() {

}

This module I build with this command:

tinygo build -o module/http_client.wasm -target=wasip1 module/http_client/main.go

My tingo version is 0.33.0

elewis787 commented 2 weeks ago

I haven't used wazero a ton but I have worked with HTTP with wasm/wasi a fair amount.

I would suggest taking a look at wasip2 support that was added and wasi-http.

I played around with implementing a custom HTTP transport here https://github.com/hayride-dev/wasi/blob/main/http/transport/transport.go

and you can see how it was used to do an http.client request here https://github.com/hayride-dev/wasi-tinygo/blob/main/main.go

This uses a lot of wasip2 elements, but it is possible to do similar flows in wasip1. I am working on cleaning up the bindings and will be releasing server handler support and client request support here soon.

In my experience, it does involve creating a custom HTTP transport that can do the translation from host ( wazero env ) to guest ( wasm module/component ) or vice versa

I would recommend taking a look at https://extism.org/docs/concepts/runtime-apis ( which if I recall correctly uses wazero ) and if you are looking at wasip2 checking out wasmtime.

Unfortunately, their Golang bindings do not support wasip2 yet tho so you would need to use Rust as your host and deploy a tinygo component that makes an HTTP client request.