HTTP & Files
Fetch makes HTTP requests straight from your WASM component and returns a Response — with the status code, headers, and body. GetFileBytes reads a file the user picked. TriggerDownload pushes a file back to the browser.
Important: You must dot-import core/wasm (import . "github.com/gothicframework/core/wasm") to use these helpers, otherwise you will get a tinygo compile error.
Note: these calls are blocking. Go's goroutine model handles concurrency for you, so always call them inside a goroutine or a CreateWasmFunc handler.
// Inside CreateWasmFunc — already runs in its own goroutine
CreateWasmFunc("load", func() {
resp, err := Fetch("https://api.example.com/data")
if err != nil {
SetText("result", "error: "+err.Error())
return
}
SetText("result", resp.Text())
})
// On mount — use the go keyword so the blocking call never freezes the WASM thread
go func() {
resp, err := Fetch("https://api.example.com/data")
if err == nil {
SetText("result", resp.Text())
}
}()The Response carries everything about the reply. Read resp.Status, check resp.OK() (true for 200–299), inspect resp.Headers, and get the body as resp.Text() (string) or resp.Bytes() (raw bytes).
// Response{ Status int; Headers map[string]string; Body []byte }
CreateWasmFunc("load", func() {
resp, err := Fetch("https://api.example.com/todos/1")
if err != nil {
SetText("result", "error: "+err.Error())
return
}
SetText("status", strconv.Itoa(resp.Status)) // "200"
SetText("ok", strconv.FormatBool(resp.OK())) // "true" for 200..299
SetText("ctype", resp.Headers["content-type"]) // "application/json"
SetText("result", resp.Text()) // body as a string
})Need more control? Pass a FetchConfig to set Method, Headers, Body, BodyBytes, or Query parameters.
CreateWasmFunc("submit", func() {
resp, err := Fetch("https://api.example.com/todos", FetchConfig{
Method: "POST",
Headers: map[string]string{"Content-Type": "application/json"},
Body: "{\"title\":\"buy milk\"}",
Query: map[string]string{"notify": "true"}, // ?notify=true
})
if err != nil {
SetText("result", "error: "+err.Error())
return
}
if resp.OK() {
SetText("result", "created!")
}
})To handle uploads, read the user's selected file with GetFileBytes and send the []byte through BodyBytes.
CreateWasmFunc("uploadFile", func() {
data := GetFileBytes("upload")
if data == nil {
SetText("status", "no file selected")
return
}
resp, err := Fetch("/api/upload", FetchConfig{
Method: "POST",
Headers: map[string]string{"Content-Type": "application/octet-stream"},
BodyBytes: data,
})
if err != nil || !resp.OK() {
SetText("status", "upload failed")
return
}
SetText("status", "uploaded!")
})Going the other way? Read resp.Bytes() for binary data and hand it to TriggerDownload as a file. Migrating from before: Fetch used to return a plain string and there was a separate FetchBytes. Now Fetch always returns a Response — use .Text() for a string and .Bytes() for bytes. FetchBytes was removed.
CreateWasmFunc("downloadReport", func() {
resp, err := Fetch("/api/report.csv")
if err != nil {
return
}
// resp.Bytes() returns the raw []byte body (read via arrayBuffer, so
// binary payloads are never UTF-8 corrupted). FetchBytes no longer exists.
TriggerDownload("report.csv", resp.Bytes(), "text/csv")
})One request, one wait. Want to fire many at once, run a callback when it finishes, or cancel in-flight requests? Learn Async Fetch next!
