Typed JSON: Encode Request Bodies
Encode[T] is the mirror of Decode[T]: it turns a typed Go struct into JSON bytes for a request body — reflection-free and generated at build time. Pair it with BodyBytes on FetchConfig to send structured data to your server.
Same rules as Decode: the type argument is explicit and T must be a struct in a net/http-free package (like src/shared). nil slices, pointers, and maps encode as null.
import (
. "github.com/gothicframework/core/wasm"
"github.com/your-org/your-app/src/shared" // the same net/http-free package
)
CreateWasmFunc("save", func() {
user := shared.User{
Name: "Ada",
Age: 36,
Username: "ada_l",
Tags: []string{"pioneer", "math"},
Address: shared.Address{City: "London", Zip: "SW1"},
}
// Encode[T] marshals a typed struct to JSON bytes — reflection-free,
// generated at build time. The type argument is explicit, like Decode.
body := Encode[shared.User](user)
resp, err := Fetch("/api/user", FetchConfig{
Method: "POST",
Headers: map[string]string{"Content-Type": "application/json"},
BodyBytes: body,
})
if err != nil || !resp.OK() {
SetText("status", "save failed")
return
}
SetText("status", "saved!")
})Because both sides import the same struct, an Encode → POST → Decode round trip preserves every field, snake_case renames included. That's the own-BFF promise: no drift between client and server.
// Round trip: the SAME shared.User survives Encode -> POST -> Decode,
// proving client and server agree on the wire format with zero drift.
CreateWasmFunc("roundtrip", func() {
sent := shared.User{Name: "Ada", Age: 36, Username: "ada_l"}
resp, err := Fetch("/api/echo", FetchConfig{
Method: "POST",
Headers: map[string]string{"Content-Type": "application/json"},
BodyBytes: Encode[shared.User](sent),
})
if err != nil {
return
}
got, err := Decode[shared.User](resp)
if err != nil {
return
}
SetText("name", got.Name) // "Ada"
SetText("user", got.Username) // "ada_l" (rename survives)
SetText("match", strconv.FormatBool(got == sent)) // "true"
})When to reach for typed JSON vs HTML. If you need the data — to branch on a field, sum a total, or build a request body — use Fetch + Decode/Encode. If you just need to drop server-rendered HTML into the page, use HTMX instead — that's next.
Want to render HTML fragments, swap the DOM, and boot nested components — all from Go? Meet the HTMX struct next!
