Guide: HTTP Client¶
This guide walks through the HTTP client example. For the full API reference, see the feature page.
Feature: HTTP Client — typed HTTP calls
examples/adapters-nethttp-client¶
The most comprehensive client demo. Demonstrates both usage patterns in five numbered sections:
- Body — POST /users with a shared contract:
contract.CreateUser.Register(builder)andcontract.CreateUser.ClientHandle()both produce the same typedRouteHandle - Path params — GET /users/{id} with
PathParam.WithCodec(...)codec validated client-side before any HTTP call is sent - Cookies + headers — GET /profile with
CallOptions.CookieParams+CallOptions.HeaderParams; empty or invalid values are rejected pre-flight - Security — GET /data with
CallOptions.CredentialFuncinjectingAuthorization: Bearer <token>; demonstrates all three cases: happy path, no credentials (401), CredentialFunc error (pre-flight abort) - OpenAPI spec — same
rest.Builderused by the server generates the full spec
Observer pattern:
- CountingObserver records calls by HTTP status code (status 0 = pre-flight abort, no request sent)
- RecordValidationError fires per failing field with location = "path", "query", "cookie", "header"
Structured error logging via errors.As + named slog.Logger:
logger := slog.Default().With("transport", "http-client")
var pathErr rest.PathParamError
if errors.As(err, &pathErr) {
logger.Warn("param rejected (no request sent)",
"param", pathErr.Name,
"cause", pathErr.Err,
)
}
→ examples/adapters-nethttp-client
Binary requests and responses (PNG, JPEG, PDF…)¶
The client (nethttp.Call) supports binary request bodies and binary response bodies the same way as JSON — register format.Binary on the route handle and the client sets headers and validates automatically.
Sending a binary request body¶
Register format.Binary via WithRequestFormats. The client calls format.Binary.Marshal (validates magic bytes and size), sets Content-Type: image/png, and sends the raw bytes as the request body:
pngCodec := codex.Bytes().
Refine(validate.MaxBytes(5 * 1024 * 1024)).
Refine(validate.PNG)
uploadHandle := uploadRoute.ClientHandle()
uploadHandle.WithRequestFormats(format.Binary(pngCodec).WithContentType("image/png"))
meta, err := nethttp.Call(ctx, client, baseURL, uploadHandle, pngBytes,
map[string]string{"id": imageID},
nethttp.CallOptions{Observer: obs},
)
The Content-Type: image/png header is set automatically from the registered format.
Receiving a binary response body¶
Register format.Binary via WithFormats. The client sets Accept: image/png, reads the raw response body, and calls format.Binary.Unmarshal (validates magic bytes and size before returning):
downloadHandle := downloadRoute.ClientHandle()
downloadHandle.WithFormats(format.Binary(pngCodec).WithContentType("image/png"))
png, err := nethttp.Call(ctx, client, baseURL, downloadHandle, downloadReq,
map[string]string{"id": imageID},
nethttp.CallOptions{Observer: obs},
)
// png is validated (magic bytes + size) — safe to write to disk or display
The Accept: image/png header is set automatically. A server that returns a different Content-Type will cause format.Binary.Unmarshal to fail constraint validation (magic-byte mismatch).
Both directions¶
A route that uploads binary and returns binary registers both:
handle.WithRequestFormats(format.Binary(pngCodec).WithContentType("image/png"))
handle.WithFormats(format.Binary(pngCodec).WithContentType("image/png"))
See examples/png-upload for upload (binary request → JSON response) and download (JSON request → binary response) routes with full codec validation.