Skip to content

(Wannabe-awesome) list of methods to make outbound HTTP(S) requests from within WebAssembly in many languages

License

Notifications You must be signed in to change notification settings

vasilev/HTTP-request-from-inside-WASM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 

Repository files navigation

Make HTTP request from inside WebAssembly

(Wannabe-awesome) list of approaches (recipes, frameworks, http client libraries, etc) to send outbound HTTP(S) requests from inside WebAssembly.

Contents

Language Browsers and V8-based runtimes Standalone / server-side / WASI runtimes
Ada

AdaWebPack

AssemblyScript

as-fetch

wasi-experimental-http, wasi-http-ts, wasi-http

BASIC

EndBASIC, gobasic

C# / .Net

Blazor, OpenSilver, System.Net.Http.HttpClient, Uno Platform

Extism PDK for .NET, Spin SDK for .NET, wasi-experimental-http, wasi-http

C / C++

Emscripten, xxhr

Extism PDK for C, httpclient_wasmedge_socket, wasi-experimental-http, wasi-http

Crystal

crystal-js

Dart

package:http, package:web, dio, fetch_api, fetch_client

Forth

WAForth

Golang / TinyGo

net/http, wasm-fetch, Nigel2392/requester, Anko, Risor, Tengo, Hogosuru, Vecty, Vugu, Yaegi

Capsule, Extism PDK for Go, go-plugin, Spin SDK for Go, stealthrocket/net, wasi-experimental-http, wasi-http, Wasm Workers Server

Haskell

Extism PDK for Haskell

Java

Bytecoder

spin-teavm-example

JavaScript

Goja, gojax/fetch, Jint, libcurl.js, Otto, quickjs-emscripten, sebastianwessel/quickjs

WasmEdge-QuickJs, Extism PDK for JS, Spin SDK for JS / TS, Wasm Workers Server

Kotlin

Kotlin/Wasm

Lisp

Janet

Lua

Wasmoon, gluahttp, lmodhttpclient, gopher-lua-libs, Pluto

PHP

php-wasm

Pascal

Free Pascal

Perl

WebPerl

Python

RustPython, Pyodide, pyodide-http, GPython, JupyterLite, PyScript, Panel, PocketPy, RPython, requests-wasm-polyfill, Stlite, urllib3, micropython-wasm

componentize-py, Extism PDK for Python, Spin SDK for Python

R

webR

Ruby

ruby.wasm

Rust

wasm-bindgen, Cloudflare Workers SDK, ehttp, gloo_net, httpc, http-client, iced, leptos, localghost, MoonZoon, reqwasm, reqwest, sauron, seed, surf, sycamore Scripting: Rune

reqwest, http_req, Extism PDK for Rust, Spin SDK for Rust, wasi-experimental-http, wasi-http, Wasm Workers Server

Starlark

starlark-go, starlark-go-nethttp, starlib, starlight, starlight-enhanced

Swift

SwiftWasm

Tcl

criTiCaL, Wacl

Wonkey

Wonkey/httprequest

Zig

Extism PDK for Zig, Spin SDK for Zig, wasi-experimental-http

Misc langs

Berry: berry

MoonBit: Extism PDK for MoonBit, Virgil: Extism PDK for Virgil

Browser WASM runtimes and V8-based runtimes like Node.js and Deno, also Bun

Ada

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

AdaWebPack

L   : aliased Listener;
xhr : Web.XHR.Requests.XML_Http_Request;

overriding procedure Handle_Event
  (Self : in out Listener; Event : in out Web.DOM.Events.Event'Class)
is
  use type Web.XHR.Requests.State;
begin
  if xhr.Get_Ready_State = Web.XHR.Requests.DONE then
    WASM.Console.Log (xhr.Get_Response_Text);
  end if;
end Handle_Event;

procedure Initialize_Example is
begin
  xhr := Web.XHR.Requests.Constructors.New_XML_Http_Request;
  xhr.Open ("GET", "https://httpbin.org/anything");
  xhr.Send ("");
  xhr.Add_Event_Listener ("readystatechange", L'Access);
end Initialize_Example;

Example

Browser

Manual JS XMLHttpRequest interop by using the wrapper for imported JS-side code.

AssemblyScript

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

as-fetch

import { fetch } from "as-fetch/assembly";

export { responseHandler } from "as-fetch/assembly";

fetch("https://httpbin.org/anything", {
  method: "GET",
  mode: "no-cors",
  headers: [],
  body: null,
}).then((resp) => {
  const text = resp.text();
});

Example

Readme

Browser, Node.js, and Deno

JS fetch interop by importing the function from runtime

BASIC

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

EndBASIC

DIM res AS STRING
' Custom function
res = HTTPGET("https://httpbin.org/anything")
PRINT res 

Example for LOGIN command

Some info

Playground

Type LOGIN "usr","pwd" there, and it will invoke a POST request

Browser

Using reqwest for API calls in REPL

gobasic

REM Custom function
res$ = HTTPGET ("https://httpbin.org/anything")
PRINT res$

Example

Readme

Browser, Bun, and Deno.

Uses Golang's "net/http" in a custom function injected into the language.

Berry

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Berry

# custom function
print(httpget('https://httpbin.org/anything'))

Example

Browser

JS XMLHttpRequest interop by invoking emscripten_fetch() from a custom host function injected as native function into Berry.

C#

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Blazor

@using System.Net.Http.Json
@inject HttpClient HttpClient

@code {
var data = await HttpClient.GetFromJsonAsync<JsonElement>(
  "https://httpbin.org/anything");
}

Example

Demo by JasonWatmore Demo source

Browser, also native server-side

JS fetch interop by calling to TS wrapper

OpenSilver

Silverlight / WPF revived in WASM form

using System;
using System.Net.Http;

HttpClient client = new HttpClient();
string uri = "https://httpbin.org/anything";
string responseText = await client.GetStringAsync(uri);

Console.WriteLine("text: " + responseText);

Doc

Demo

Browser

System.Net. Http.HttpClient

Standard library

using System;
using System.Net.Http;

HttpClient client = new HttpClient();
string uri = "https://httpbin.org/anything";
string responseText = await client.GetStringAsync(uri);

Console.WriteLine("body: " + responseText);

Example

Doc

Browser, Node, Bun, and Deno.

JS fetch interop by calling to TS wrapper

Uno Platform

// Uno Platform's own way
// Deprecated since .NET 6,
// use 'System.Net.Http.HttpClient' and 'HttpHandler' instead
// See https://github.com/unoplatform/uno/issues/9665
using System.Net.Http;

using (var handler = new Uno.UI.Wasm.WasmHttpHandler())
using (var client = new HttpClient(handler))
{
var request = new HttpRequestMessage(HttpMethod.Get,
  new Uri("https://httpbin.org/anything"));
var response = await client.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
}

Test

Tutorial

Playground

Browser

JS Interop invokes the TS wrapper for fetch

C / C++

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Emscripten

#include <emscripten/fetch.h>

void requestOnSuccess(emscripten_fetch_t *fetch)
{
    char dat[fetch->numBytes + 1];
    memcpy(dat, fetch->data, fetch->numBytes);
    dat[fetch->numBytes] = '\0';
    printf("data: %s \n", dat);
    emscripten_fetch_close(fetch);
}

emscripten_fetch_attr_t attr;
emscripten_fetch_attr_init(&attr);
strcpy(attr.requestMethod, "GET");
attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
attr.onsuccess = requestOnSuccess;
emscripten_fetch(&attr, "https://httpbin.org/anything");

Doc

Browser

JS XMLHttpRequest interop mapped to be used in emscripten_fetch().

nxxm/xxhr

#include <xxhr/xxhr.hpp>

using namespace xxhr;
 
GET( "https://httpbin.org/anything"s, 
  on_response = [](auto res) { std::cout << res.text; }
);

Example

Doc

Browser, Node.js, and Deno

JS XMLHttpRequest Interop

Crystal

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

lbguilherme/crystal-js

require "js"

class XMLHttpRequest < JS::Reference
  @[JS::Method]
  def self.new : self
    <<-js
      return new XMLHttpRequest();
    js
  end

  js_getter responseText : String

  js_method send
  js_method open(method : String, url : String, async : Int32)
end

req = XMLHttpRequest.new
req.open("GET", "https://httpbin.org/anything", 0)
req.send
JS.console.log req.response_text

Readme

Browser, Node.js, and Deno

Manual JS XMLHttpRequest interop by creating the wrapper using crystal-js shard.

Dart

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

package:dio

import 'package:dio/dio.dart';

final dio = Dio();
Response response = await dio.get(
  'https://httpbin.org/anything');
print(response);

Readme

Browser with Wasm-GC support enabled1

JS XMLHttpRequest interop inside BrowserHttpClientAdapter class.

package:fetch_api

import 'package:fetch_api/fetch_api.dart';

final resp = await fetch(
  'https://httpbin.org/anything');
final txt = await resp.text();
print('${txt}');

Some doc

Browser with Wasm-GC support enabled1, Node.js, and Deno.

JS fetch interop using imported by @JS function.

package:fetch_client

import 'package:fetch_client/fetch_client.dart';

final client = FetchClient(
  mode: RequestMode.cors);
final uri = Uri.parse(
  'https://httpbin.org/anything');
final resp = await client.get(uri);

print('${resp.body}');
client.close();

Some doc

Browser with Wasm-GC support enabled1, Node.js, and Deno.

Extends the BaseClient by using imported package:fetch_api.

package:http

import 'package:http/http.dart' as http;

final resp = await http.get(
  Uri.parse('https://httpbin.org/anything'));
print('${resp.body}');

Doc

Browser with Wasm-GC support enabled1

JS XMLHttpRequest interop inside BrowserClient class.

package:web

import 'package:web/web.dart' as web;

final resp = await web.window.fetch(
  'https://httpbin.org/anything'.toJS).toDart;
final txt = await resp.text().toDart;
print('${txt}');

Example

Doc

Browser with Wasm-GC support enabled1

Direct fetch interop with help of some extension types.

Forth

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

WAForth

: URL$  S" https://httpbin.org/anything" ;
( custom word )
URL$ HTTPGET

Readme

Browser, NodeJS, Bun, and Deno.

JS fetch interop by invoking a custom host function, bound info Forth's dictionary/namespace.

Golang

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Golang

import "net/http"

resp, err := http.Get("https://httpbin.org/anything")

fetch options

Browser and Node.js

JS fetch Interop

marwan.io/wasm-fetch

Save 4 MB of wasm binary size

import "marwan.io/wasm-fetch"

resp, err := fetch.Fetch("https://httpbin.org/anything", 
    &fetch.Opts{})

if err == nil {
	println(string(resp.Body))
}

Example

Doc

Browser and Node.js

Direct JS fetch Interop

Nigel2392/requester

import "github.com/Nigel2392/requester"

var client = requester.NewAPIClient()
client.Get("https://httpbin.org/anything").Do(
  func(response *http.Response) {
    body, err := io.ReadAll(response.Body)
    if err == nil {
        fmt.Println(string(body))
    }
  }
)

Sources

Browser and maybe Node.js

Uses Golang's "net/http"

Hogosuru

SPA framework

import (
"github.com/realPy/hogosuru"
"github.com/realPy/hogosuru/base/fetch"
"github.com/realPy/hogosuru/base/promise"
"github.com/realPy/hogosuru/base/response"
)

f, err := fetch.New("https://httpbin.org/anything", nil)
f.Then(func(r response.Response) *promise.Promise {
  txtpromise, _ := f.Then(
    func(r response.Response) *promise.Promise {
      if prm, err := r.Text(); hogosuru.AssertErr(err) {
        return &prm
      }
      return nil
    }, nil)

  txtpromise.Then(func(i interface{}) *promise.Promise {
    fmt.Println(i.(string))
    return nil
  }, nil)
return nil
}, nil)

Browser

Manual low-level JS fetch and XMLHttpRequest interop using Go wrappers for Web API: fetch, XHR.

Vecty

UI library

import "io"
import "log"
import "net/http"

go func() {
  resp, _ := http.Get(action.Url)
  defer resp.Body.Close()
  body, _ := io.ReadAll(resp.Body)
  log.Println(string(body))
}()

Browser

Has no built-in solutions, just directly invoking Golang's "net/http"

Vugu

UI library

import "io"
import "log"
import "net/http"

resp, _ := http.Get("https://httpbin.org/anything")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
log.Println(string(body))

Example

Possible with Dev Container

Browser

Has no built-in solutions, just directly invoking Golang's "net/http"

Yaegi

It's VM / interpreter

import (
  "fmt"; "io"; "net/http"
)

resp, _ := http.Get("https://httpbin.org/anything")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))

Example

Some doc

Browser, Bun, and Deno.

Directly invoking Golang's "net/http" via mapping.

Golang-like languages

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Anko

var http = import("net/http")
var ioutil = import("io/ioutil")

var url = "https://httpbin.org/anything"
res, _ = http.DefaultClient.Get(url)
b, _ = ioutil.ReadAll(res.Body)
println(toString(b))
res.Body.Close()
Browser and maybe Node

Directly invoking Golang's "net/http" via mapping.

Risor

url := "https://httpbin.org/anything"
resp := fetch(url)
print(resp.text())

Doc

Browser and maybe Node

Using Golang's "net/http" via mapping.

TengoHTTP

for Tengo

fmt := import("fmt")
http := import("httpclient")

resp := http.request("https://httpbin.org/anything", "GET")
fmt.print(is_error(resp) ? resp : resp.body)

Readme

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping.

Java / JVM

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

mirkosertic/Bytecoder

transpile JVM bytecode to Wasm

import de.mirkosertic.bytecoder.api.web.*;

final Window win = Window.window();
final Console con = Console.console();

win.fetch("https://httpbin.org/anything").then(
 new Promise.Handler<Response>() {
  @Override
  public void handleObject(final Response resp) {
    resp.text().then(new StringPromise.Handler() {
      @Override
      public void handleString(final String text) {
        con.log(text);
      }
    });
  }
});

Test

Some doc

Browser, Node.js, and Deno

Direct fetch
interop using imported JS window object.

JavaScript

Using browser's own JavaScript VM

Possible, but why?

Libraries to use from JavaScript
Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

libcurl.js

Requires server-side counterpart

libcurl.set_websocket(
  'wss://your-wisp-proxy.yoursite.tld/');
let res = await libcurl.fetch(
  'https://httpbin.org/anything');
console.log(await res.text());

Doc

Browser

Tunneling TCP to WebSocket using protocols "wisp" or "wsproxy" .

JavaScript VM or interpreter compiled to WASM

JavaScript built with Emscripten
Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

quickjs-emscripten

// Host function
const txt = await fetch('https://httpbin.org/anything');
console.log(txt);

Example

Doc

Browser, Bun, Deno, and Node.

JS fetch interop by injecting a custom host function into QuickJS's global namespace.

sebastianwessel/quickjs

const fn = async () => {
 // Host function   
 const res = await fetch(
   'https://httpbin.org/anything');

 return res.text();
}

export default await fn();

Doc

Bun, Deno, and Node.

Wrapper over quickjs-emscripten, uses host function fetch().

JavaScript implemented in .NET
Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Jint

// custom object
http.get('https://httpbin.org/anything');

Example

Readme

Browser

Using .NET's "Http.HttpClient" via mapping a custom object inside JS.

JavaScript implemented in Golang
Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Goja

const res = httpget('https://httpbin.org/anything');
console.log(res);

Example

Some doc

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping a custom function inside JS.

gojax/fetch

fetch('https://httpbin.org/anything')
  .then(function(res) {
    return res.text();
  }).then(function(txt) {
    console.log(txt);
    exitloop();
  });

Readme

Browser, Bun, and Deno.

Injecting a custom function into JS. That func uses the goproxy as HTTP client, which is a wrapper for Golang's "net/http".

Otto

const res = httpget('https://httpbin.org/anything');
console.log(res);

Example

Some doc

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping a custom function inside JS.

Kotlin

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Kotlin/Wasm

still Alpha

import kotlinx.browser.window

window.fetch("https://httpbin.org/anything").then {
  if (it.ok) {
    it.text().then {
      println(it)
      null
    }
  }
  null
}

Readme

Browser with Wasm-GC and Wasm-Exception-Handling support enabled1, Node v21 and above, Deno v1.38 and above.

Direct fetch interop using exposed JS window object. For Node/Deno, just import.

Lisp

Clojure-like languages

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Janet

# custom function
(print (httpget `https://httpbin.org/anything`))

Example

Some doc

Browser and maybe Node

JS XMLHttpRequest interop by invoking emscripten_fetch() from a custom host function injected into Janet.

Lua

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Wasmoon

local resp = fetch('https://httpbin.org/anything'):await()
local text = resp:text():await()
print(text)

Example

Some doc

Dev Container

Browser, Node.js, and Deno

Direct fetch interop by manually importing it into Lua using lua.global.set().

Lua implemented in Golang

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

cjoudrey/gluahttp

local http = require('http')
local res, err = http.request('GET', 
  'https://httpbin.org/anything', {
  headers={
    ['User-Agent']='gluahttp/wasm'
  }
})
print(res.body)

Example

Readme

Browser and maybe Node

Using Golang's "net/http" via mapping.

gopher-lua-libs

local http = require('http')
local client = http.client()
local req = http.request('GET', 
  'https://httpbin.org/anything')
local res, err = client:do_request(req)
print(res.body)

Doc

Browser and maybe Node

Using Golang's "net/http" via mapping.

erdian718/lmodhttpclient aka ofunc/lmodhttpclient

local io = require('io')
local httpclient = require('http/client')

local res = httpclient.get(
  'https://httpbin.org/anything')
io.copy(res, io.stdout)
res:close()

Example

Readme

Browser and maybe Node

Using Golang's "net/http" via mapping.

Lua dialects

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Pluto

local http = require 'pluto:http'

http.request('https://httpbin.org/anything')
|> print

Browser and maybe Node.

JS XMLHttpRequest interop by invoking emscripten_fetch().

PHP

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

php-wasm

Fork of PIB

$url = 'https://httpbin.org/anything';

$window = new Vrzno();
$window->fetch($url)
->then(function($res) { return $res->text(); })
->then(var_dump(...));

Browser, Bun, Deno, Node, and CloudFlare Workers.

Manual JS fetch interop using vrzno PHP extension.

Pascal

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Free Pascal

function httpGet(url: ShortString; Var str_out:
    ShortString): ShortString; external 'js';

var out_str : ShortString;
begin
        out_str:= DupeString( ' ' , 255 );
        httpGet('https://httpbin.org/anything', out_str);
        writeln(out_str);
end.

Example

Browser and maybe Node

Direct XMLHttpRequest interop in sync mode via importing the JS function into Pascal with mapping.

Perl

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

WebPerl

use WebPerl qw/js js_new sub_once/;

my $xhr = js_new('XMLHttpRequest');
$xhr->addEventListener('load', sub_once {
    print 'Done: '.$xhr->{responseText};
});
$xhr->open('GET', 'https://httpbin.org/anything', 0);
$xhr->send();

Forum post

Browser, Node.js, and Deno

Manual JS XMLHttpRequest interop using WebPerl.pm module.

Python

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

RustPython

from browser import fetch

fetch('https://httpbin.org/anything').then(
    lambda resp: print((resp)))

Example

Playground

source of demo

Browser, Node.js, and maybe Deno

JS fetch Interop

Pyodide

from pyodide.http import pyfetch

response = await pyfetch("https://httpbin.org/anything")

Also note that the pyodide-http is bundled in Pyodide.

pyodide.http Doc

Browser, Node.js, and maybe Deno

JS fetch Interop

koenvo/pyodide-http

requests and urlopen in Pyodide

# needs `await micropip.install(['pyodide-http', 'requests'])`

import pyodide_http     
pyodide_http.patch_all()

import requests
response = requests.get("https://httpbin.org/anything")

Supported packages

Playground

Browser and maybe Node.js

JS fetch and XMLHttpRequest Interop using Pyodide's js scope.

urllib3

Since 2.2.0

import micropip
await micropip.install('urllib3')

import urllib3
res = urllib3.request('GET', 'https://httpbin.org/anything')
print(res.data.decode('utf-8'))
# using requests
import micropip
await micropip.install('requests')

import requests
res = requests.get('https://httpbin.org/anything')
print(res.text)

Doc

Playground

Browser only (yet)

JS fetch interop or XMLHttpRequest interop if fetch is not available.

GPython

import httpclient

print(httpclient.Get('https://httpbin.org/anything'))

Example

Some doc

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping.

PyScript

from pyodide.http import pyfetch, FetchResponse
import asyncio

async def req() -> FetchResponse:
  response = await pyfetch("https://httpbin.org/anything")
  print(await response.string())

asyncio.ensure_future(req())

Example

Doc

Browser

Uses pyodide's facilities

Panel

response = requests.get("https://httpbin.org/anything")

Doc

Browser

Employs koenvo/pyodide-http. Also direct XMLHttpRequest interop for image data.

JupyterLite

# using Pandas
import pyodide_http; pyodide_http.patch_all()
import pandas as pd

data = pd.read_json('https://httpbin.org/json')
data
# using js.fetch
from js import fetch
res = await fetch('https://httpbin.org/anything')
text = await res.text()
print(text)
# using requests
import micropip; await micropip.install(['requests'])
import pyodide_http; pyodide_http.patch_all()

import requests
res = requests.get("https://httpbin.org/anything")
print(res.text)

Doc

Playground

Browser

Employing pyodide-http and Pyodide's own facilities.

requests-wasm-polyfill

For pyjs

import requests

r = requests.get('https://httpbin.org/anything')
result = r.text
print(result)

Example

Browser

Direct XMLHttpRequest interop in sync mode.

micropython-wasm

import js

fetch = JS('fetch')

response = fetch('https://httpbin.org/anything').wait()
text = response.text().wait()
print(text)

Readme

Browser and Node.js

Direct fetch interop using js module, by employing Emscripten APIs.

Stlite

a port of Streamlit to Wasm

from pyodide.http import pyfetch
import streamlit as st

response = await pyfetch("https://httpbin.org/anything")
body = await response.string()
st.write(body)

Readme

Playground

Browser

Uses pyodide's facilities.

PocketPy

lightweight Python 3.x

# custom module
import http

print(http.get('https://httpbin.org/anything'))

Example

Some doc

Browser

JS XMLHttpRequest interop by invoking emscripten_fetch() from a custom host function injected as module function into Python.

Python-like languages

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

soIu/rpython

It's compiler

from javascript import Object, asynchronous, JSON

@asynchronous
def send_request(url):
  fetch = Object('fetch')
  res = fetch.call(url).wait()
  text = res['text'].call().wait()
  print(text)
  return text
  
def target(*args): return main, None

def main(argv):
  send_request('https://httpbin.org/anything')
  return 0

if __name__ == '__main__':
  import sys
  main(sys.argv)

Example

Some doc

Browser, Node.js, and Deno

Direct fetch interop using javascript module, by employing Emscripten APIs.

R

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

webR

df <- read.csv("https://httpbin.org/anything")
print(df)
// All works: read.table() variants, download.file(), scan(), url(), etc

Doc

Browser and Node

Implemented xhr transport which uses JS XMLHttpRequest interop by calling web worker using Emscripten APIs.

Ruby

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

ruby.wasm

require 'js'

resp = JS.global.fetch('https://httpbin.org/anything').await
puts resp.text.await

Doc

Browser, Node.js, and maybe Deno

Direct JS fetch Interop

Rust

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

wasm-bindgen

let window = web_sys::window().unwrap();
let resp_val = JsFuture::from(
  window.fetch_with_str("https://httpbin.org/anything")).await?;

Example

Fetch API docs

Demo

Prints to browser console, source

Browser, Node.js, and Deno

JS fetch Interop

Rust SDK for writing Cloudflare Workers aka workers-rs

let mut resp = Fetch::Url(
  "https://httpbin.org/anything"
    .parse().unwrap(),
)
.send().await?;
let txt = resp.text().await?;

Doc

workerd, Cloudflare's JavaScript/ Wasm Runtime

JS fetch interop using wasm-bindgen

ehttp

let request = ehttp::Request::get("https://httpbin.org/anything");
ehttp::fetch(request, move |result: ehttp::Result<ehttp::Response>| {
    println!("Text: {:?}", result.unwrap().text());
});

Example

Doc

Demo

Browser, Node.js, and Deno.

Also native

JS fetch Interop using wasm-bindgen

httpc

let uri = Uri::from_static("https://httpbin.org/anything");
let req = Request::get(uri).body(None).unwrap();
let client = web_sys::window();
let resp = client.issue(req).await.unwrap();
println!("{}", resp.body());

Test

Doc

Browser, Node.js, and Deno.

Also native

JS fetch Interop using wasm-bindgen

http-client

use http_client::HttpClient;
use http_types::{Method, Request};
use http_client::wasm::WasmClient as Client;

let client = Client::new();
let req = Request::new(Method::Get, "https://httpbin.org/anything");
client.send(req).await.unwrap();
dbg!(client);

Example

Doc

Browser, Node.js, and Deno

Also native (and others).

JS fetch Interop using wasm-bindgen

Gloo's gloo-net

use gloo_net::http::Request;

let resp = Request::get("https://httpbin.org/anything").send()
    .await.unwrap();

Doc

Demo

source

Browser, Node.js, and Deno

JS fetch Interop using wasm-bindgen

Iced

// uses reqwest

let txt = reqwest::get("https://httpbin.org/anything")
  .await?.text().await?;

log::info!("text: {}", txt);

Browser

Has no built-in solutions, just uses any suitable 3rd-party lib, such as: reqwest.

Leptos

// uses reqwasm or gloo_net for CSR

use leptos_dom::logging::console_log;

let txt = reqwasm::http::Request::get(
    "https://httpbin.org/anything")
  .send().await?.text().await?;
console_log(txt.as_str());

Browser

Also server-side rendering (SSR)

Has no built-in solutions, just uses any suitable 3rd-party lib, such as: reqwest, gloo_net, reqwasm.

localghost

use localghost::prelude::*;
use localghost::{log, net};

let res = net::Request::get(
  "https://httpbin.org/anything").send().await?;
log::info!("text: {:?}", res.body_string().await?);

Doc

Browser and maybe Node

JS fetch Interop using wasm-bindgen

MoonZoon

use zoon::{println, *};

let txt = reqwest::get("https://httpbin.org/anything")
  .await?
  .error_for_status()?
  .text()
  .await?;
println!("text: {}", txt);

Example

Doc

Browser

Has no built-in solutions, just uses any suitable 3rd-party lib, such as: reqwest.

reqwest

let txt = reqwest::get("https://httpbin.org/anything")
    .await?.text().await?;

println!("Text: {:?}", txt);

Doc

Browser, Node.js, and Deno

Also native

JS fetch Interop using wasm-bindgen

reqwasm

use reqwasm::http::Request;

let resp = Request::get("https://httpbin.org/anything").send()
    .await.unwrap();

Example

Doc

Browser, Node.js, and Deno

Wrapper for gloo_net

sauron

use sauron::dom::{Http, spawn_local};

spawn_local(async move {
  let txt = Http::fetch_text(
    "https://httpbin.org/anything").await.unwrap();
  log::trace!("{}", txt);
});

Doc

Browser

Also server-side rendering (SSR)

JS fetch interop using wasm-bindgen

Seed

use seed::{prelude::*, *};

let response = fetch("https://httpbin.org/anything").await?;
let body = response.text().await?;

Example

Browser, Node.js, and Deno

JS fetch interop using wasm-bindgen

surf

let mut resp = surf::get("https://httpbin.org/anything").await?;
println!("{}", resp.body_string().await?);

Example

Doc

Browser, Node.js, and Deno

Also native

Uses http-rs/http-client as WASM backend

sycamore

// uses reqwasm
use reqwasm::http::Request;

let url = "https://httpbin.org/anything";
let res = Request::get(&url).send().await?;

let txt = res.text().await?;
log::info!("{}", txt);

Browser

Has no built-in solutions, just uses any suitable 3rd-party lib, such as: reqwasm.

Scripting languages for Rust

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Rune

let req = http::get(
  "https://httpbin.org/anything").await?;
let txt = req.text().await?;
println(txt);

Some doc

Playground

Browser

Uses reqwest.

Starlark

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

starlark-go

# custom function
print(httpget('https://httpbin.org/anything'))

Example

Readme

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping a custom function inside Starlark.

starlark-go-nethttp

res = http.get('https://httpbin.org/anything')
print(res.body)

Readme

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping.

qri-io/starlib

"Starlark's missing stdlib"

load('http.star', 'http')

res = http.get('https://httpbin.org/anything')
print(res.body())

Doc

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping.

starlight-go/starlight

# custom function
print(httpget('https://httpbin.org/anything'))

Example

Readme

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping a custom function inside Starlark.

Starlight Enhanced

Maintained fork of Starlight

# custom function
print(httpget('https://httpbin.org/anything'))

Example

Readme

Browser, Bun, and Deno.

Using Golang's "net/http" via mapping a custom function inside Starlark.

Swift

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

SwiftWasm

import JavaScriptEventLoop
import JavaScriptKit

JavaScriptEventLoop.installGlobalExecutor()

let fetch = JSObject.global.fetch.function!
let resp = try! await JSPromise(
  fetch("https://httpbin.org/anything").object!)!.value
let text = try! await JSPromise(resp.text().object!)!.value
print(text)

Browser, Node.js, and Deno

Direct fetch interop using JavaScriptKit framework

Tcl

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

criTiCaL

# custom command
puts [httpget "https://httpbin.org/anything"]

Example

Readme

Browser, Bun, and Deno.

Uses Golang's "net/http" in a custom command injected into the language.

Wacl

set func_ptr_number 2
puts [::wacl::jscall $func_ptr_number "string" "string" "https://httpbin.org/anything"]

Needs a JavaScript-side function registered using jswrap():

wacl.onReady(function (interpreter) {
  const wrappedFuncName = interpreter.jswrap(function (ptrUrl) {
    const url = interpreter.ptr2str(ptrUrl);
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, false);
    xhr.send();
    return interpreter.str2ptr(xhr.responseText);
  }, 'string', 'string');
});

Readme

Demo / Playground

Browser

Manual JS XMLHttpRequest interop by registering a function on JS side using jswrap() via Emscripten addFunction() API and then calling it using ::wacl::jscall by its registration number.

Wonkey

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Wonkey/httprequest

Local request := New HttpRequest
request.ReadyStateChanged = Lambda()
  If request.ReadyState = ReadyState.Done Then
    Print "Body: " + request.ResponseText
  End
End

request.Open("GET", "https://httpbin.org/anything")
request.Send()

Some doc

Browser

JS fetch interop using Emscripten APIs.

Standalone and server-side runtimes (mostly WASI and WASI-Socket-enabled), incl containers, FaaS, Edge Computing, etc

AssemblyScript

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

wasi-experimental-http

import { 
  Method, RequestBuilder, Response 
} from "@deislabs/wasi-experimental-http";
import { Console } from "as-wasi/assembly";

let resp = new RequestBuilder("https://httpbin.org/anything")
    .header("User-Agent", "wasm32-wasi-http")
    .method(Method.GET)
    .send();

let text = String.UTF8.decode(resp.bodyReadAll().buffer);
Console.log(text);

Readme

Dev Container created by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork or old Spin

Importing npm package which calls imported host function implemented in wasi-experimental-http-wasmtime Wasmtime's WASI module.

brendandburns/wasi-http-ts

// Identical to wasi-experimental-http currently
// Needs `npm i https://github.com/brendandburns/wasi-http-ts`
import { 
  Method, RequestBuilder 
} from "@brendandburns/wasi-http-ts";
import { Console } from "as-wasi/assembly";

let resp = new RequestBuilder("https://httpbin.org/anything")
    .header("User-Agent", "wasm32-wasi-http")
    .method(Method.GET)
    .send();

let text = String.UTF8.decode(resp.bodyReadAll().buffer);
Console.log(text);

<--

Readme from dev-wasm-ts

Possible with Dev Container created by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Using client lib which calls imported host function implemented in wasi-experimental-http-wasmtime Wasmtime's WASI module.

wasi-http

implementations:

  1. wasmtime-wasi-http

  2. stealthrocket/wasi-go

import { Console } from "as-wasi/assembly";
import { request } from "./request";
export function cabi_realloc(a: usize, b: usize,
                             c: usize, len: usize): usize {
 return heap.alloc(len);
}

let response = request("GET", "https://httpbin.org/anything", null,
  [{ name: "User-Agent", value: "wasi-http" }]);

Console.log(response.Body);

Example

Readme

Dev Container by brendandburns

  1. Wasmtime version 9.0 and above.
  2. Wazero in wasi-go version 0.7 and above

Calling to imported

  1. Wasmtime's host function, which, in turn, performs real request using hyper: https, http.

  2. Wazero's host function, which performs a request using "net/http".

C# / .Net

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for .NET

using Extism;

var req = new HttpRequest(
    "https://httpbin.org/anything")
{
    Method = HttpMethod.GET
};
var res = Pdk.SendRequest(req);
Pdk.SetOutput(res.Body);

Doc

Dev Container

  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Calling C-level-imported runtime's host function exported for plugins, which makes actual request using ureq.

Spin SDK for .NET

using Fermyon.Spin.Sdk;
using System.Net;

var req = new HttpRequest { Url = "https://httpbin.org/anything" };
var resp = HttpOutbound.Send(req);

Example

Doc

Spin (uses Wasmtime)

C level binding to
Spin's host function.

wasi-experimental-http

using Wasi.Http;

var client = new HttpClient(new WasiHttpHandler());
var result = await client.GetAsync("https://httpbin.org/anything", 
 System.Threading.CancellationToken.None);
var content = await result.Content.ReadAsStringAsync();
Console.WriteLine(content);

Example

Readme

Dev Container created by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Calling imported via C level bindings the host function implemented in wasi-experimental-http-wasmtime Wasmtime's WASI module.

wasi-http

implementations:

  1. wasmtime-wasi-http

  2. stealthrocket/wasi-go

// *Still* identical to wasi-experimental-http's code. 
using Wasi.Http;

var client = new HttpClient(new WasiHttpHandler());
var result = await client.GetAsync("https://httpbin.org/anything", 
 System.Threading.CancellationToken.None);
var content = await result.Content.ReadAsStringAsync();
Console.WriteLine(content);

Example

Readme

Dev Container by brendandburns

  1. Wasmtime version 9.0 and above.
  2. Wazero in wasi-go version 0.7 and above

Sequence: .Net -> C -> WASI

Calling imported C-level Mono binding which calls generated (by wit-bindgen from the wit template) code, which calls imported

  1. Wasmtime's host function, which, in turn, performs real request using hyper: https, http.

  2. Wazero's host function, which performs a request using "net/http".

C / C++

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for C

#define EXTISM_IMPLEMENTATION
#include "extism-pdk.h"
#include <stdint.h>
#include <string.h>

int32_t EXTISM_EXPORTED_FUNCTION(httpget) {
  const char *r = "{\"url\": \"https://httpbin.org/anything\"}";
  ExtismHandle req = extism_alloc_buf_from_sz(r);
  ExtismHandle res = extism_http_request(req, 0);

  extism_output_set_from_handle(res, 0, extism_length(res));
  return 0;
}

Doc

Dev Container

  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Calling C-level-imported runtime's host function exported for plugins, which makes actual request using ureq.

httpclient_wasmedge_socket

// no SSL support yet
std::array<char, 4096> buf{};
fetchIO *io = fetchGetURL("http://httpbin.org/anything", "4");
int nbytes = fetchIO_read(io, buf.data(), buf.size());
fetchIO_close(io);
std::cout << buf.data() << std::endl;

Example

WasmEdge

Raw socket write using WasmEdge Socket SDK for C/C++, which imports Wasmedge's implementation of WASI Socket

wasi-experimental-http

#include "req.h"
#include <string.h>
#include <stdio.h>

const char* url =  "https://httpbin.org/anything";
const char* headers = "User-agent: wasm32-wasi-http";
size_t length = 1024 * 1024;
char* buffer = (char*) malloc(length);
uint16_t code;
ResponseHandle handle;

HttpError err = req(url, strlen(url), "GET", 3, headers, 
  strlen(headers), "", 0, &code, &handle);

size_t written;
err = bodyRead(handle, buffer, length, &written);
close(handle);

printf("%s\n", buffer);

free(buffer);

Example

Readme

Dev Container created by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Calling imported host function implemented in wasi-experimental-http-wasmtime Wasmtime's WASI module.

wasi-http

implementations:

  1. wasmtime-wasi-http

  2. stealthrocket/wasi-go

// snippet, expand it for full code
types_outgoing_request_t request = types_new_outgoing_request(
        &method, &path, &query, &scheme, &domain, headers);

response = default_outgoing_http_handle(request, NULL);

types_future_incoming_response_get(response, &result);

types_incoming_response_consume(result.val.ok, &stream);

streams_read(stream, len, &body_res, &err);

#include "proxy.h" // Generated by wit-bindgen
// from https://github.com/WebAssembly/wasi-http/tree/main/wit
#include <stdio.h>

void http_handle(uint32_t arg, uint32_t arg0) {}

int main() {
    types_headers_t headers = types_new_fields(NULL);
    types_method_t method = {.tag = TYPES_METHOD_GET};
    types_scheme_t scheme = {.tag = TYPES_SCHEME_HTTPS};
    proxy_string_t path, domain, query;
    proxy_string_set(&domain, "httpbin.org");
    proxy_string_set(&path, "/anything");
    proxy_string_set(&query, "");

    types_outgoing_request_t request = types_new_outgoing_request(
        &method, &path, &query, &scheme, &domain, headers);
    types_future_incoming_response_t response;

    response = default_outgoing_http_handle(request, NULL);

    proxy_result_incoming_response_error_t result;
    types_future_incoming_response_get(response, &result);

    types_incoming_stream_t stream;
    types_incoming_response_consume(result.val.ok, &stream);

    int32_t len = 16 * 1024;
    proxy_tuple2_list_u8_bool_t body_res;
    streams_stream_error_t err;
    streams_read(stream, len, &body_res, &err);

    printf("Response body: %s\n", body_res.f0.ptr);

    proxy_tuple2_list_u8_bool_free(&body_res);
    types_drop_outgoing_request(request);
    streams_drop_input_stream(stream);
    types_drop_incoming_response(result.val.ok);

    return 0;
}

Example

Readme

Dev Container by brendandburns

  1. Wasmtime version 9.0 and above.
  2. Wazero in wasi-go version 0.7 and above

Calling a function generated by wit-bindgen from the wit template, which calls the

  1. Wasmtime's host function, which, in turn, performs real request using hyper: https, http.

  2. Wazero's host function, which performs a request using "net/http".

Golang (Tinygo)

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Capsule

import (
    hf "github.com/bots-garden/capsule/capsulemodule/hostfunctions"
)
res, err := hf.Http("https://httpbin.org/anything", "GET", nil, "")

Example

HTTP request docs

wazero

wazero's Host Functions feature

Extism Plug-in Development Kit (PDK) for (Tiny)Go

import "github.com/extism/go-pdk"

req := pdk.NewHTTPRequest("GET", "https://httpbin.org/anything")
resp := req.Send()

pdk.OutputMemory(resp.Memory())

Example

Doc

Extism uses Wasmtime

Calling C-level-imported runtime's host function exported for plugins, which makes actual request using ureq.

knqyf263/go-plugin

hostFunctions := protobufs.NewHostFunctions()

resp, err := hostFunctions.HttpGet(ctx,
  &protobufs.HttpGetRequest{Url: "https://httpbin.org/anything"})

Readme

Dev Container

go-plugin uses wazero

Invoking the
bound host function.

Spin SDK for (Tiny)Go

import (
    spinhttp "github.com/fermyon/spin/sdk/go/http"
)

resp, err := spinhttp.Get("https://httpbin.org/anything")

Spin (uses Wasmtime)

C level binding to
Spin's host function.

wasi-experimental-http

response, err := Request(
  "https://httpbin.org/anything", "GET",
  "User-agent: wasm32-wasi-http", "")
defer response.Close()

body, err := response.Body()
if err == nil {
  println(string(body))
}

Example

Readme

Dev Container created by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Calling imported host function implemented in wasi-experimental-http-wasmtime Wasmtime's WASI module.

wasi-http

implementations:

  1. wasmtime-wasi-http

  2. stealthrocket/wasi-go

import (
  "io/ioutil"
  "net/http"
  wasiclient "github.com/dev-wasm/dev-wasm-go/client"
)

client := http.Client{
  Transport: wasiclient.WasiRoundTripper{},
}
response, err := client.Get("https://httpbin.org/anything")
defer response.Body.Close()

body, err := ioutil.ReadAll(response.Body)
if err == nil {
  println(string(body))
}

Example

Readme

Dev Container by brendandburns needs plenty of RAM to compile (~4G), so may cause OOM on 2-core instance

  1. Wasmtime version 9.0 and above.
  2. Wazero in wasi-go version 0.7 and above

Sequence: Go -> C -> WASI

Calling a method generated by wit-bindgen from the wit template. That method calls the generated C-level-bound function, which calls the imported

  1. Wasmtime's host function, which, in turn, performs real request using hyper: https, http.

  2. Wazero's host function, which performs a request using "net/http".

stealthrocket/net

Use gotip until Go 1.21 is released.

import ( 	"fmt" ; "io" ; "net/http"
  _ "github.com/stealthrocket/net/http"
)

response, err := http.Get("http://httpbin.org/anything")
if err != nil {
  fmt.Println(err)
}
defer response.Body.Close()

body, err := io.ReadAll(response.Body)
if err == nil {
  fmt.Println(string(body))
}

Readme

Dev Container

Wazero and WasmEdge

Hotpatching on module import http.DefaultTransport with wasip1.DialContext which refers to imported sock_conn() in the case of WasmEdge and to syscall.Connect() in the case of Wazero.

VMware OCTO / Wasm Workers Server

import (
  "log"; "net/http"
  "github.com/vmware-labs/wasm-workers-server/kits/go/worker"
)

req, _ := http.NewRequest(http.MethodGet,
  "https://httpbin.org/anything", nil)
res, _ := worker.SendHttpRequest(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
log.Println(string(body))

Example

Doc

Wasm Workers Server uses Wasmtime

Calling to Go-wrapped, to C-wrapped, to C-level imported host function which makes request using reqwest.

Haskell

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for Haskell

module Main where

import Extism.PDK
import Extism.PDK.HTTP

https_get = do
  let url = "https://httpbin.org/anything"
  let req = newRequest url
  resp <- sendRequest req Nothing
  outputMemory (memory resp)

foreign export ccall "https_get" https_get :: IO ()

main = https_get

Example

Doc

Extism uses Wasmtime

Calling imported runtime's host function exported for plugins, which makes actual request using ureq.

Java

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

dicej/spin-teavm-example

Uses forked TeaVM as compiler.

import wit_wasi_outbound_http.WasiOutboundHttp.*;

Result<Response, HttpError> result =
  WasiOutboundHttp.request(
    new Request(Method.GET, "https://httpbin.org/anything", 
    new ArrayList<>(), new ArrayList<>(), null));

Response resp = result.getOk();
String body = new String(resp.body, UTF_8);

Example

Readme

Spin (uses Wasmtime)

Direct invocation of imported Spin's host function.

JavaScript and TypeScript

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

wasmedge-quickjs

import { fetch } from 'http'

const res = await fetch('https://httpbin.org/anything')
print(await res.text())

Doc

Dev Container

WasmEdge

Distinguished by URL scheme raw socket write to (1) WasiTcpConn which is wrapper to Wasmedge's implementation of WASI Socket or (2) WasiTlsConn which is wrapper to wasmedge_rustls_api.

Extism Plug-in Development Kit (PDK) for JavaScript

function https_get() {
  let resp = Http.request(
    {
      url: 'https://httpbin.org/anything',
      method: 'GET',
      headers: { 'User-Agent': 'extism_pdk' }
    },
    null
  );
  Host.outputString(resp.body);
}
module.exports = { https_get }

Example

Some doc

Extism uses Wasmtime

Http object injected into QuickJS's global namespace. It calls the http::request() from Extism PDK for Rust.

Spin SDK for JavaScript

const resp = await fetch('https://httpbin.org/anything');
const decoder = new TextDecoder('utf-8');
const body = decoder.decode(await resp.arrayBuffer());

Example

Spin (uses Wasmtime)

Invocation of bound JS SDK function, which calls via Rust Spin SDK Spin's host function.

Spin SDK for TypeScript

const resp = await fetch('https://httpbin.org/anything');
const body = await resp.text();

Example

Spin (uses Wasmtime)

Invocation of bound JS SDK function, which calls via Rust Spin SDK Spin's host function.

VMware OCTO / Wasm Workers Server

const resp = await fetch('https://httpbin.org/anything');
const txt = await resp.text();
console.log(txt);

Example

Doc

Wasm Workers Server uses Wasmtime

Calling bound to JS send_http_request() the host function
which makes request using reqwest.

MoonBit

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for MoonBit

Experimental

pub fn https_get() -> Int {
  let req : Unit = @http.new_request(
    @http.Method::GET,
    "https://httpbin.org/anything",
  )
  let resp : Unit = req.send()
  resp.output()
  return 0
}
  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Calling imported runtime's host function exported for plugins, which makes actual request using ureq.

Python

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

componentize-py

import poll_loop
from proxy.imports.types import (
  SchemeHttps, OutgoingRequest )

req = OutgoingRequest(Fields.from_list([]))
req.set_scheme(SchemeHttps())
req.set_authority('httpbin.org')
req.set_path_with_query('/anything')

resp = await poll_loop.send(req)

stream = poll_loop.Stream(resp.consume())
buf = b''
while True:
  chunk = await stream.next()
  if chunk is None:
    break
  else:
    buf += chunk

print(buf.decode('utf-8'))

Example

Readme

Wasmtime version 15.0, maybe incl. Spin.

Genetaring Python bindings to wasi-http based on wit files under the scenes during componentize process.

Extism Plug-in Development Kit (PDK) for Python

import extism

@extism.plugin_fn
def httpget():
  res = extism.Http.request(
    'https://httpbin.org/anything')
  extism.output_str(res.data_str())

Example

Readme

Dev Container

  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Http.request() method calls the FFI function injected into Python's "native" ffi module. It calls the http::request() from Extism PDK for Rust.

Spin SDK for Python

from spin_http import Request, http_send

response = http_send(
  Request('GET', 
  'https://httpbin.org/anything', 
  {}, None))

print(str(response.body, 'utf-8'))

Example

Spin (uses Wasmtime)

A Python spin_http module calls imported via Rust Spin SDK Spin's host function.

Rust

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for Rust

use extism_pdk::*;

#[plugin_fn]
pub fn https_get(_: ()) -> FnResult<Memory> {
  let req = HttpRequest::new("https://httpbin.org/anything");
  let resp = http::request::<()>(&req, None)?;
  Ok(resp.into_memory())
}

Possible with Dev Container by brendandburns

  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Calling C-level-imported runtime's host function exported for plugins, which makes actual request using ureq.

http_req_wasi

use http_req::request;

let mut writer = Vec::new();
let res = request::get("https://httpbin.org/anything", 
    &mut writer).unwrap();
println!("body: {}", String::from_utf8_lossy(&writer));

Example

Doc

WasmEdge

Writes to wasmedge_wasi_socket stream. For SSL, the stream is wrapped with rustls's stream.

Spin SDK for Rust

let mut res = spin_sdk::http::send(
  http::Request::builder()
  .method("GET")
  .uri("https://httpbin.org/anything")
  .body(None)?,
)?;

Spin (uses Wasmtime)

Calling imported Spin's host function.

reqwest_wasi

as part of

WasmEdge Sockets

Any code based on WasmEdge's forks of tokio-rs or mio is expected to work in Wasmedge runtime

let res = reqwest::get("https://httpbin.org/anything").await?;
let body = res.text().await?;
println!("text: {}", body);

Example

WasmEdge

Wrapping internal stream with WasmEdgeTls, which is built on top of WasmEdge's implementation of WASI Socket.

wasi-experimental-http

use http;
use wasi_experimental_http;

let req = http::request::Builder::new()
  .uri("https://httpbin.org/anything").body(None).unwrap();
let resp = wasi_experimental_http::request(req);
let data = std::str::from_utf8(&resp.body_read_all().unwrap())
  .unwrap().to_string();
println!("{}", data);

Test

Doc

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Calling imported Wasmtime's host function. The actual request is here.

wasi-http

implementations:

  1. wasmtime-wasi-http

  2. stealthrocket/wasi-go

let headers = types::new_fields(&[("User-agent", "WASI-HTTP")]);
let request = types::new_outgoing_request(
  types::MethodParam::Get, "/anything", "",
  Some(types::SchemeParam::Https), "httpbin.org", headers,
);

let future_response = default_outgoing_http::handle(request, None);

types::drop_outgoing_request(request);
let response = types::future_incoming_response_get(future_response)
  .ok_or_else(|| anyhow!("response is available immediately"))?
  .map_err(|err| anyhow!("response error: {err:?}"))?;
types::drop_future_incoming_response(future_response);
let stream = types::incoming_response_consume(response)
  .map_err(|()| anyhow!("response has no body stream"))?;
let mut body = Vec::new();
let mut is_eof = false;
while !is_eof {
  let (mut chunk, stream_at_end) = streams::read(stream, u64::MAX)?;
  is_eof = stream_at_end;
  body.append(&mut chunk);
}
streams::drop_input_stream(stream);
types::drop_incoming_response(response);
println!("body: {}", str::from_utf8(&body).unwrap());

Example

Readme

Possible with Dev Container by brendandburns

  1. Wasmtime version 9.0 and above.
  2. Wazero in wasi-go version 0.7 and above

Rust code generated (by wit-bindgen from the wit template) calls imported

  1. Wasmtime's host function, which, in turn, performs real request using hyper: https, http.

  2. Wazero's host function, which performs a request using "net/http".

VMware OCTO / Wasm Workers Server

let req = Request::builder()
  .uri("https://httpbin.org/anything")
  .body(String::new()).unwrap();

let res = bindings::send_http_request(req).unwrap();

let data = res.body();
let txt = String::from_utf8_lossy(&data);
println!("text: {txt}");

Example

Doc

Wasm Workers Server uses Wasmtime

Calling imported host function which makes request using reqwest.

Virgil

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for Virgil

var req = Http.newRequest(Method.GET, 
  "https://httpbin.org/anything");
def res = req.send(null);

res.output();

Example

Readme

  • Extism uses Wasmtime
  • Extism CLI uses Wazero

Calling C-level-imported runtime's host function exported for plugins, which makes actual request using ureq.

Zig

Product / ImplementationTLDR: UsageTLDR: Example code Doc Online demo WASM RuntimeInternals: method to do real request

Extism Plug-in Development Kit (PDK) for Zig

const std = @import("std");
const extism_pdk = @import("extism-pdk");
const allocator = std.heap.wasm_allocator;

export fn https_get() i32 {
const plugin = extism_pdk.Plugin.init(allocator);
var req = extism_pdk.http.HttpRequest.init(allocator, "GET", 
  "https://httpbin.org/anything");
defer req.deinit();
req.setHeader("User-Agent", "extism_pdk") catch unreachable;

const resp = plugin.request(req, null) catch unreachable;
defer resp.deinit();

plugin.outputMemory(resp.memory);
return 0;
}

Example

Some doc

Extism uses Wasmtime

Calling imported runtime's host function exported for plugins, which makes actual request using ureq.

Spin SDK for Zig

Unofficial

const spin = @import("spin");

const req = spin.http.Request{ .method = .GET, 
  .url = "https://httpbin.org/anything" };
const res = spin.http.send(req) catch unreachable;

Example

Spin (uses Wasmtime)

Calling to C-level import of Spin's host function.

wasi-experimental-http

var gp_all = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gp_all.allocator();
var status: u16 = 0;
var handle: u32 = 0;

_ = request("https://httpbin.org/anything", "GET", "", "", &status, &handle);
defer _ = close(@bitCast(i32, handle));

var headers_buffer = try allocator.alloc(u8, 1024);
var header_len: u32 = 0;
_ = header(handle, "content-length", headers_buffer, &header_len);
const length = try std.fmt.parseInt(u32, headers_buffer[0..header_len], 10);
var buffer = try allocator.alloc(u8, length + 1);
defer allocator.free(buffer);

var written: u32 = 0;
_ = body_read(handle, &buffer[0], @bitCast(i32, buffer.len), &written);
try std.io.getStdOut().writer().print("{s}\n", .{buffer[0..written]});

Example

Doc

Dev Container by brendandburns

Wasmtime with integrated wasi-experimental-http crate, e.g. brendandburns's fork

Calling imported Wasmtime's host function. The actual request is here.

Footnotes

  1. Firefox 120+, and all based on Chrome(ium) 119+. 2 3 4 5 6

About

(Wannabe-awesome) list of methods to make outbound HTTP(S) requests from within WebAssembly in many languages

Topics

Resources

License

Stars

Watchers

Forks