Skip to Content
How-To GuidesGoHTTP Request and Response Parameter Mapping (Go)

HTTP Request and Response Parameter Mapping (Go)

Overview

When a Go agent is exposed over HTTP (see golem-add-http-endpoint-go), the platform maps parts of each request onto the agent’s constructor (ID) fields and the method’s input struct fields. This skill covers how path segments, query parameters, headers, and the request body bind to those fields, which Go types each binding accepts, and how return types map to HTTP responses.

Binding is metadata only and declared on the definition: the mount Path on Spec.HTTP and the golem.HTTP(...) option on each method. There is no incoming-request handler in the guest.

Steps

  1. Name fields to match wire names. A path/query/header variable refers to an input field by its schema name: the Go field name in lowerCamelCase with each initialism as one word, so MaxResults is maxResults, SKU is sku, UserID is userId and APIKey is apiKey.
  2. Bind path variables by putting {name} in the mount path (binds ID fields) or an endpoint path suffix (binds method input fields).
  3. Bind query and header values inline (?name={field}) or with golem.Query / golem.Header.
  4. Leave body fields unbound on body-carrying verbs; they arrive as JSON.

Path variables

{var} segments bind by schema name.

  • Mount path {var}s bind the agent’s constructor (ID) fields. Every ID field must appear as a {var} so a request selects one instance.
  • Endpoint path {var}s bind the method’s input fields.
type ID struct{ Name string } // bound by {name} in the mount type LookupIn struct { SKU string Detailed bool } var Agent = golem.DefineAgent[ID](golem.Spec{ Name: "CatalogAgent", HTTP: &golem.Mount{Path: "/catalog/{name}"}, // {name} → ID.Name }) // GET /catalog/{name}/items/{sku} — {sku} → LookupIn.SKU var Lookup = Agent.Method[LookupIn, ItemInfo]("lookup", golem.HTTP(golem.GET("/items/{sku}", golem.Query("detailed", "detailed"))))

The trailing catch-all {*rest} captures everything after a prefix and may only appear as the last endpoint segment; it is not allowed in a mount path.

Query parameters

Two equivalent forms. Inline ?name={field} in the path suffix, or golem.Query(wire, field) when the wire name differs from the field:

type SearchIn struct { Query string MaxResults uint64 } // GET /catalog/{name}/search?q=hello&limit=10 var Search = Agent.Method[SearchIn, []Result]("search", golem.HTTP(golem.GET("/search", golem.Query("q", "query"), // ?q= → SearchIn.Query golem.Query("limit", "maxResults"), // ?limit= → SearchIn.MaxResults )))

Inline golem.GET("/search?q={query}&limit={maxResults}") is equivalent when the parameter name matches the field’s wire name.

Header variables

golem.Header(wire, field) maps a request header to an input field:

type DataIn struct { RequestID string Token string } var GetData = Agent.Method[DataIn, Data]("getData", golem.HTTP(golem.GET("/data", golem.Header("X-Request-Id", "requestId"), golem.Header("Authorization", "token"), )))

Header names are matched case-insensitively; binding the same header twice on one endpoint is a definition error.

Supported types for path, query, and header bindings

A value bound from a URL path/query/header string must decode into a scalar Go field. Only these kinds bind:

Go typeBound from
stringused as-is
bool"true" / "false"
int8, int16, int32, int64signed integer
uint8, uint16, uint32, uint64unsigned integer
float32, float64floating-point number

Binding a non-scalar field (struct, slice, map) from path/query/header is a definition error: “cannot bind input field … only scalar fields decode from a URL”. Such fields must arrive in the body instead.

Prefer sized integers throughout. Bare int/uint are rejected at the agent-schema level because their width is platform-dependent (see golem-add-agent-go).

Request body mapping

For body-carrying verbs (POST, PUT, DELETE, PATCH, …), any input field not bound to a path/query/header binding is populated from the JSON request body:

type UpdateIn struct { SKU string // from the path Name string // from the body Count uint64 // from the body } // POST /catalog/{name}/items/{sku} Body: {"name":"Widget","count":5} var Update = Agent.Method[UpdateIn, Item]("update", golem.HTTP(golem.POST("/items/{sku}")))

Each unbound field becomes a top-level key in the JSON body object (keyed by schema name, as elsewhere in the SDK).

GET and HEAD are bodyless: they carry no request body, so they must bind every input field from path/query/header. An unbound field on a bodyless verb is a definition error.

Return type to HTTP response mapping

Handlers return their output value; the platform maps it to a response. In Go:

Return typeHTTP statusBody
golem.Unit204 No Contentempty
T (any type)200 OKJSON-serialized T
*T200 OK if non-nil, 404 Not Found if nilJSON T or empty
golem.Result[T, E]200 OK on Ok, 500 Internal Server Error on ErrJSON T or JSON E
golem.Result[*T, E]200 OK on Ok with a value, 404 Not Found on Ok(nil), 500 on ErrJSON T, empty, or JSON E
golem.UnstructuredBinary[M]200 OKraw bytes with Content-Type (default application/octet-stream)
golem.UnstructuredText[L]200 OKtext/plain; charset=utf-8 (plus Content-Language when set)
an unstructured value with URL set307 Temporary RedirectLocation = the URL

golem.Unit is the empty result placeholder; *T is Golem’s option<T> (a nil pointer means “absent”, as does golem.Option[T]); golem.Result[Ok, Err] returns the error as an observable value (see golem-add-agent-go on returning failures).

The value inside an option or an Ok follows the same rules as a top-level value. An unstructured value nested in *T, golem.Result[T, E] or golem.Result[*T, E] is sent as the raw body (or a redirect), not as JSON:

// 200 raw bytes / 404 when missing / 500 with a JSON DownloadError var Download = Agent.Method[DownloadIn, golem.Result[*golem.UnstructuredBinary[golem.AnyMimeType], DownloadError]]( "download", golem.HTTP(golem.GET("/files/{id}")))

Data type to JSON mapping

Go typeJSON
stringstring
sized ints / uintsnumber (integer)
float32, float64number
boolboolean
[]Tarray
structobject keyed by schema names (MaxResults → maxResults, UserID → userId)
*Tvalue or null
map[K]Vobject / WIT map

Key Constraints

  • A variable can bind an input field from exactly one of path/query/header — binding it more than once is a definition error.
  • Bindable path/query/header fields must be scalar; non-scalars go in the body.
  • Bodyless verbs (GET, HEAD) must bind every input field.
  • Field references on the wire use the schema name, the field name in lowerCamelCase with each initialism as one word (SKU → sku, RequestID → requestId).
  • A raw (non-JSON) body is a single body field of type golem.UnstructuredBinary[M] or golem.UnstructuredText[L]; M/L is golem.AnyMimeType/golem.AnyLanguage or a marker type whose MimeTypes()/Languages() lists what is accepted. Any other body is a JSON object keyed by the schema names.
GuideDescription
golem-add-http-endpoint-goThe high-level workflow of mounting an agent and adding routes
golem-add-http-auth-goRequire authentication on endpoints
golem-add-cors-goAllow cross-origin requests
golem-add-agent-goDefine the agent and its input/output types