httpbind

package module
v0.5.34 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 19, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

tinybind-go

日本語

Reflection-free, code-generation-first binding for TinyGo and standard Go. Runtime dependencies are isolated into HTTP, JSON, SQL, and DynamoDB packages.

User guides: httpbind · jsonbind · cborbind · configbind · tomlbind · htmlbind · sqlbind · dynamobind · firestorebind · cachekeybind · reloadable components · fasthttp backend · size and shape limits

Building a framework on top of this? Start with framework facilities, the index of what is available to you and what is not, then htmlbind for framework owners and, if your users will build against fasthttp, the fasthttp backend for framework owners. Owning a browser runtime as well? Client behaviour covers server actions, client handlers, and component parameters in one place.

Define request/response structs once. The generator emits type-specific binders and writers, so the same model covers JSON, form, multipart, and query (plus path / header / cookie via tags). Responses adapt to the client Accept (and streaming negotiation where used). From the same analysis it also generates OpenAPI 3.1 (JSON), kept in sync with binders and writers, with godoc comments carried into summary / description. Route registration is discovered by static analysis of real net/http styles (HandleFunc, Handle, method values, wrappers, and so on)—not by a separate DSL.

type CreateUserRequest struct {
	// input = query + payload (JSON / form / multipart). Tag may be omitted.
	Name  string `input:"name"`  // same as untagged: Name string
	Email string `input:"email"` // same as untagged: Email string
	OrgID string `path:"org_id"`
	Token string `header:"Authorization"`
}

type CreateUserResponse struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
	OrgID string `json:"org_id"`
}

func createUserHandler(w http.ResponseWriter, r *http.Request) {
	input, err := httpbind.Bind[CreateUserRequest](r)
	if err != nil {
		httpbind.WriteError(w, r, err)
		return
	}
	// Name/Email: query and/or JSON/form/multipart body (input).
	// OrgID from path, Token from Authorization header.
	out := CreateUserResponse{
		ID:    "u_1",
		Name:  input.Name,
		Email: input.Email,
		OrgID: input.OrgID,
	}
	_ = httpbind.Write[CreateUserResponse](w, r, out)
}

Run the generator on the package (binders + OpenAPI embed):

go run ./cmd/tinybind-gen generate -dir . -openapi

The same generation pass also supports CLI-only application subcommands through configbind.SubCommand[T], including required, optional, and rest positional arguments. See the configbind subcommand guide.

Struct tag reference

Wire name defaults to the lower-camel field name when a tag value is omitted (e.g. untagged Name → "name").

Tag Source Notes
(none) or input:"name" query + payload Default. Payload covers JSON, application/x-www-form-urlencoded, and multipart/form-data. Tag is optional when the field is plain user input.
query:"page" query only Not read from the body.
payload:"name" body only JSON / form / multipart by Content-Type. Not read from the query string.
payload:"image" on httpbind.File multipart file part Binds filename, content type, size, and bytes from the named part. Payload-only (not query). Multipart bodies are capped at 1 MiB by default; override with httpbind.SetMaxMultipartBodyBytes.
path:"org_id" path parameter Matches {org_id} (or equivalent) in the route pattern.
header:"Authorization" request header Header name is the tag value.
cookie:"session" cookie Cookie name is the tag value.

input vs payload vs query

  • Prefer input (or no tag) for normal fields that may arrive as query or body.
  • Use query / payload only when you must restrict the origin (e.g. search filters in the query string, body-only JSON fields).
  • payload is not the same as input: it does not accept query parameters.

Example that mixes restrictions:

type SearchRequest struct {
	Keyword string `query:"keyword"`   // query only
	Page    int    `query:"page"`
	Filter  string `payload:"filter"`  // body only (JSON/form/multipart)
}

Response structs commonly use standard json:"..." names for encoding; request binding still uses the source tags above.

Streaming (ideal API)
httpbind.WriteStream(w, r, func(s *httpbind.Stream[ChatEvent]) error {
    if err := s.Write(ChatEvent{Type: "delta", Delta: "hi"}); err != nil {
        return err
    }
    return s.Write(ChatEvent{Type: "done"})
})
  • Write can be called many times (incremental events).
  • Format is chosen once when the stream opens, from ?stream=, Accept, User-Agent, then default NDJSON.
  • The entry closes the stream, so the trailing ] of the JSON array framing is written even when the callback fails halfway.
  • Formats:
    • SSE — text/event-stream
    • NDJSON / JSONL — application/x-ndjson (one object per line; not a JSON array)
    • JSON array — application/json as [obj1,obj2,...] (Close writes the trailing ])
  • Do not use removed helpers WriteNDJSON / WriteSSE.

Packages

Path Role
. (package httpbind) Runtime: Bind / Write / WriteError / WriteStream / OpenAPI serve / SwaggerUI
jsonbind/ Standalone DecodeJSON / EncodeJSON runtime; does not import net/http or database/sql
tomlbind/ Standalone DecodeTOML runtime over minitoml; the TOML layer of configbind without its env, CLI, or config-dir parsers
sqlbind/ ScanRows runtime and row helpers; does not import net/http
dynamobind/ DynamoDB item runtime over tinygodriver/nosql/dynamodb; does not import net/http or database/sql
firestorebind/ Firestore Datastore-mode entity runtime over tinygodriver/nosql/datastore; does not import net/http or database/sql
cachekeybind/ Cache key framing runtime; stdlib only
generator/ Field-plan binders/writers + OpenAPI 3.1 + template generation
parser/ Route/handler discovery (Bind, Write, WriteStream, errors)
templates/htmlbind/ Typed, context-safe HTML template compiler
templates/sqlbind/ Typed, parameterized SQL template compiler
templates/firestorebind/ Typed Firestore access-pattern declarations (.tb.firestore)
cmd/tinybind-gen CLI: binders + OpenAPI + templates from a package dir
examples/demo End-to-end sample app
internal/* Test fixtures
testdata/cmd/* Dev-only helpers (not for distribution; under testdata so go get / ./... skip them)
go run ./cmd/tinybind-gen generate -dir ./path/to/package

Every generated file records a // tinybind:generated comment holding the SHA-256 of the inputs that produced it, so a run whose package sources, templates, go.mod, options, and generator binary all hash to the recorded value exits without regenerating. -force regenerates regardless. See docs/httpbind.md.

The CLI automatically discovers .tb.html and .tb.sql files in the target package and writes tinybind_templates_gen.go. A package containing SQL templates must name its database with -sql-dialect postgresql, mysql, or sqlite; there is no default. SQL value expressions become driver arguments, and placeholders are generated in encounter order in the style that dialect requires — $1, $2, … for PostgreSQL and ? for MySQL and SQLite:

package store

type User { id: int, name: string }

export statement FindUser(id: int): sql.optional<User> {
SELECT id, name FROM users WHERE id = {id}
}

This generates both BuildFindUser(id) (Statement, error) and the FindUser(ctx, db, id) (*User, error) convenience API. The SQL compiler also supports sql.exec, sql.one<T>, sql.many<T>, private sql.predicate composition, private sql.relation<T> subqueries, conditional clauses, and array value-list expansion. Hand-authored placeholders and unguarded UPDATE/DELETE statements are rejected.

sql.many<T> streams rows as iter.Seq2[T, error] without first allocating a result slice. Query, scan, and iteration errors are yielded as the error value, and stopping the range early closes the underlying sql.Rows:

for user, err := range FindUsers(ctx, db, filter) {
    if err != nil {
        return err
    }
    // consume user
}

Web frameworks can opt in to executor-from-Context wrappers while the explicit db APIs remain available:

go run ./cmd/tinybind-gen generate -dir ./path/to/package -sql-context-api

The generated FindUsersContext(ctx, filter) resolves the *sql.DB, *sql.Conn, or *sql.Tx installed with sqlbind.WithSQLExecutor. This allows transaction middleware to keep the executor inside its callback Context:

web.Transaction(func(ctx context.Context) error {
    for user, err := range FindUsersContext(ctx, filter) {
        if err != nil {
            return err
        }
        // consume user within the transaction
    }
    return nil
})

Custom generator commands may use a framework-owned Context key by setting a resolver with the signature func(context.Context) (SQLExecutor, error); setting it also enables the Context wrappers:

options.SQLExecutorResolver = &generator.SymbolPattern{
    PackagePath: "example.com/web/dbctx",
    Name:        "Executor",
}

Frameworks may wrap the runtime functions and still make those calls visible to the generator. Register the wrapper's package identity, semantic operation, and the zero-based positions of only the type/value roles that the generator needs:

package main

import "github.com/shibukawa/tinybind-go/generator"

func main() {
    calls := generator.NewCallRegistry()
    if err := calls.Register(
        // func RegisterConfig[T any](ctx context.Context, name string) *T
        generator.ConfigBindCall(
            generator.Function("example.com/framework", "RegisterConfig"),
            generator.GenericType("config", 0),
            generator.Argument("prefix", 1),
        ),
        // func Created(ctx context.Context, w http.ResponseWriter, value any) error
        generator.ResponseWriteStatusCall(
            generator.Function("example.com/framework", "Created"),
            generator.ArgumentType("response", 2),
            generator.Constant("status", 201),
        ),
    ); err != nil {
        panic(err)
    }
    options, err := calls.Options(generator.DefaultOptions())
    if err != nil {
        panic(err)
    }
    generator.Main(generator.MustCommandSet(generator.GenerateCommand(options)))
}

Extra wrapper arguments do not need to be described. Use GenericType when the model comes from a generic type argument, ArgumentType when it comes from a value argument's static type, Argument for a runtime value such as a config prefix or route pattern, and Constant when the wrapper hides a fixed value such as status 201. The available operations have matching constructors: RequestBindCall, ResponseWriteCall, ResponseWriteStatusCall, StreamCreateCall, JSONDecodeCall, JSONEncodeCall, RowsScanCall, ConfigBindCall, ConfigSubCommandCall, RouteRegisterCall, and ErrorResponseCall. Function targets package functions; Method targets named-receiver methods.

The required role names, in the same order, are request; response; response + status; stream; decode; encode; row; config + prefix; config + name + help; pattern + handler; and status.

RuntimePackages remains a shorthand for functions with the standard tinybind names and signatures. Use explicit call patterns for renamed wrappers, reordered arguments, extra arguments, or hidden constants. generator.Options{} deliberately has no discovery identities. Add a feature to DisableFeatures to prevent discovery even under -generate-all.

A framework can combine the built-in generate command with its own lifecycle commands:

commands := generator.MustCommandSet(
    generator.GenerateCommand(options),
    generator.Command{Name: "init", Summary: "initialize a project", Run: runInit},
    generator.Command{Name: "build", Summary: "generate and build", Run: runBuild},
    generator.Command{Name: "watch", Summary: "watch, generate, and build", Run: runWatch},
)
generator.Main(commands)

Each command receives a context.Context, arguments, and injected CommandIO containing stdin/stdout/stderr, working directory, and environment. A build or watch implementation can generate in-process without invoking a CLI:

result, err := generator.New(options).GeneratePackage(ctx, generator.GenerateRequest{
    Dir: dir, OpenAPI: true,
})

GeneratePackage runs template, mapping, configbind, and optional OpenAPI generation and returns the written paths. generator.Main is only the outer process boundary; tests and composed commands should call CommandSet.Run or GeneratePackage directly.

Generation is usage-aware: a package that only calls DecodeJSON[T] gets only its JSON decoder, imports jsonbind, and does not import the root HTTP runtime or net/http. Set Options.GenerateAll for the legacy all-enabled-mappings mode. Compatible multipart file aliases can be listed in Options.FileTypes.Set.

Standalone JSON uses the dependency-isolated package:

value, err := jsonbind.DecodeJSON[Document](reader)
err = jsonbind.EncodeJSON(writer, value)

JSON reads are capped at 1 MiB by default, and objects and arrays may nest 10000 deep, matching encoding/json. jsonbind returns transport-neutral errors; httpbind.Bind maps an oversized HTTP request to status 413 and a malformed one to 400. Every limit a request can run into — bodies, nesting, uploads, WebSocket messages, and the ones the transport owns rather than this module — is collected in size and shape limits.

Joined SQL rows can be grouped into an object tree with generated, reflection-free ScanRows[T] code:

type Organization struct {
    ID    int    `db:"organization_id" groupkey:""`
    Name  string `db:"organization_name"`
    Users []User
}
type User struct {
    ID   int    `db:"user_id" groupkey:""`
    Name string `db:"user_name"`
}

organizations, err := sqlbind.ScanRows[Organization](rows)

Every grouped struct level has one groupkey field. Repeated keys merge into the same object; a NULL child key represents an absent outer-join child.

Formatting templates

.tb.html, .tb.sql, and .tb.dynamo are file formats this module invented, so no editor knows how to format them. The generator ships the formatter:

go run ./cmd/tinybind-gen fmt -w -dir ./store

-l lists the files that would change and exits non-zero, which is the CI form. -as sql (or html, dynamo) filters one source from stdin to stdout, which is what an editor "format on save" hook needs.

What it does per format:

  • SQL — one clause per line, CTE bodies and subqueries indented under their own SELECT, JOIN and its ON split, AND/OR aligned when a condition list is long. Keyword case, literals, and comments are left exactly as written.
  • HTML — one tag per line inside head, table, and the other positions where the HTML parser discards whitespace anyway. Elsewhere a line break only replaces whitespace that was already there, so <b>a</b><i>b</i> stays glued and rendering never changes. pre, textarea, script, style, and any preserve-whitespace subtree are copied byte for byte.
  • DynamoDB — table then key, one clause per line.

A source that does not parse is reported and left untouched. Everything the command does is available as a library:

import "github.com/shibukawa/tinybind-go/templates/templatefmt"

formatted, err := templatefmt.Source("users.tb.sql", source, templatefmt.Options{})
results, err := templatefmt.Dir("./store", templatefmt.Options{Width: 120})

templatefmt.Dir reads but never writes; each Result reports whether the file would change and carries Write() for when you want it applied.

Template positions in generated Go

Generated Go is output, not source, so an error inside it names a file you never wrote. -template-line-directives maps the generated code back to the template line that produced it, using Go //line directives:

go run ./cmd/tinybind-gen generate -dir ./store -template-line-directives

A type error in a template expression then reports store/users.tb.sql:5 instead of a line of tinybind_templates_gen.go, and every reader that honours the directive follows: the compiler, go vet, delve, gopls, and your editor. Generated lines that came from no template keep reporting against the generated file.

The path written into the directive is absolute. The toolchain shortens it against wherever you ran the command, so the same string reads as store/users.tb.sql from the module root and ./users.tb.sql from inside the package — and go build and go vet agree on it, which no relative form manages. -trimpath normalises it in the binary exactly as it does any other source path, so a release build carries yourmodule/store/users.tb.sql.

How far it reaches depends on the dialect:

  • SQL — a statement is emitted as a real Go function, so a panic inside one names the .tb.sql file in its stack frame as well.
  • HTML — compile time only. Rendering walks an instruction list inside the shared htmlbind coordinator, so a failing render's frames are in that package and no directive on generated code can move them.
  • DynamoDB — one mapping per declaration. The parser records a line and no column, so there is nothing finer to map.

It is off by default, and two things are worth knowing before turning it on. Enabling it rewrites every generated file that carries a template — with absolute paths in it, so its bytes now depend on where the checkout lives. That costs nothing if you keep generated Go out of version control, and misleads every other machine if you commit it. It also grows the mapped parts of it by roughly a third: a directive is repeated per line, because one that is not only maps the line directly below it. Comments reach no binary, so this is source size and nothing else. Second, a covered test run under directives writes a profile that keeps the generated file's path while using the mapped line numbers, so go tool cover renders against lines that do not exist in the file it names — leave the flag off for coverage.

Taking Artifact values instead of written files? The directive that ends a mapped span has to name the file you write it as, and only you know that name:

content := generator.ResolveTemplatePositions(artifact.Content, artifact.OutputBase+"_pw_gen.go")

Skipping that call misreports generated scaffolding and leaves every template position intact.

Demo

go generate ./examples/demo
go run ./examples/demo
# http://localhost:8080/       index + browser stream demo
# http://localhost:8080/docs/  Swagger UI
# http://localhost:8080/chat   WriteStream (SSE / NDJSON / JSON array auto)

See examples/demo/README.md for full curl recipes.

Benchmarks

Generated code has no reflection to drive and no intermediate map[string]any to build, which is where the difference comes from. Measured on an Apple M3, Go 1.27.0, darwin/arm64, best of 10 runs.

Each pair produces the same output: the JSON codecs are checked against encoding/json by differential fuzzing, and the handler and template pairs are asserted equivalent by the tests sitting beside the benchmarks. Reproduce with:

go test ./internal/benchfixture -run xxx -bench . -benchmem
Throughput

The document is a 312-byte order with a nested object, a three-element array of objects, and a string array. The page is a five-row user list.

Path Standard library Generated
JSON decode (io.Reader) 2381 ns · 1889 B · 18 allocs 428 ns · 752 B · 4 allocs
JSON decode (json.Unmarshal, bytes in hand) 1753 ns · 496 B · 10 allocs —
JSON encode 866 ns · 288 B · 2 allocs 227 ns · 0 B · 0 allocs
Bind + Write (request reused) 783 ns · 1154 B · 14 allocs 371 ns · 529 B · 6 allocs
Bind + Write (incl. request construction) 1601 ns · 7024 B · 28 allocs 1140 ns · 6399 B · 20 allocs
HTML render (html/template vs htmlbind) 6421 ns · 2705 B · 107 allocs 1197 ns · 72 B · 2 allocs

The JSON comparisons are against encoding/json; the handler row against a hand-written net/http handler doing the same decode, path, and header reads; the HTML row against an html/template template rendering the same document.

Encoding allocates nothing: generated encoders append into a pooled buffer, so a response costs no garbage at all. Decoding's four allocations are the two slices in the result, the body buffer, and its reader. The document's eleven strings come from a small cache the decoder keeps across calls, which serves a value it has seen before rather than allocating it again; this benchmark decodes one document repeatedly, so every string is a hit. On a stream of documents whose values all differ, each string is allocated once as before. The HTML render's two allocations are per render rather than per row, so a longer page costs the same two: the bound page and its parameters, and the writer's conversion buffer; the renderer itself comes from a pool.

Binary size

The same small JSON program built two ways, once over encoding/json and once over generated jsonbind codecs. jsonbind does not import encoding/json at all, so the reflection-based codec never enters the binary. Built with Go 1.26.5 and TinyGo 0.41.1; the native rows are darwin/arm64.

Build encoding/json jsonbind Saved
go build 3,075,666 2,565,106 −511 KB (−16.6%)
go build -ldflags="-s -w" 2,061,138 1,708,034 −353 KB (−17.1%)
tinygo build (native) 474,256 293,632 −181 KB (−38.1%)
tinygo build (native) + strip 287,856 187,968 −100 KB (−34.7%)
tinygo build -target wasi 1,264,464 738,966 −525 KB (−41.6%)
tinygo build -target wasi -no-debug 488,762 222,564 −266 KB (−54.5%)

Stripping makes the gap matter more, not less: once debug information is gone, the reflection machinery is a larger share of what is left. On a stripped TinyGo wasm build it is about half the binary.

The wasm and native rows strip differently because the debug information lives in different places. A wasm binary embeds its DWARF, which is what -no-debug removes; a Mach-O binary never carries it (macOS keeps DWARF in a separate dSYM), so -no-debug changes nothing there and strip, which drops the symbol table, is the flag's native equivalent.

encoding/json/v2

encoding/json/v2 and jsontext are stable as of Go 1.27, which this module now declares, so the comparison compiles as it stands — the locally bumped go.mod it used to need is no longer part of the invocation. It still sits behind an opt-in build tag, because it measures whether v2 is worth switching to rather than being something an ordinary go build or go test ./... should reach:

go test ./internal/benchfixture -tags tinybind_jsonv2bench -run xxx -bench JSON -benchmem
Path v1, flag off v1, flag on v2 API Generated
decode (io.Reader) 3543 ns · 1688 B · 30 2536 ns · 1889 B · 18 1650 ns · 544 B · 11 799 ns · 856 B · 15
decode (bytes in hand) 3352 ns · 888 B · 25 1871 ns · 496 B · 10 1525 ns · 496 B · 10 —
encode 587 ns · 144 B · 1 1330 ns · 1824 B · 11 943 ns · 288 B · 2 274 ns · 0 B · 0

Turning the flag on and changing nothing else is a real improvement for decoding, because the v1 API is reimplemented over v2 — but watch the encode row, which gets 2.3× slower and allocates 12× more. The flag is not free either way.

Generating onto jsontext, the v2 tokenizer, was the interesting option: the same key-switch shape driven by ReadToken lands on 13 allocations with a reused decoder — exactly what jsonbind.Parser allocates — but takes 1320 ns to do it, and 1804 ns · 1600 B · 38 allocs when the decoder is constructed per call, as a codec entry point would have to.

Size settles it. On the same small program, the experiment costs:

Build Flag off Flag on
go build 3,075,522 3,887,730 (+26%)
go build -ldflags="-s -w" 2,061,010 2,598,722 (+26%)
tinygo build -target wasi 1,345,144 2,217,774 (+65%)
tinygo build -target wasi -no-debug 496,869 881,891 (+78%)

A stripped wasm build with the experiment on is 3.5× the size of the same program on jsonbind. For a library whose first-class target is TinyGo, that rules v2 out as a dependency, and nothing in the speed columns argues for carrying a second implementation behind a build tag to get it.

TinyGo

TinyGo is a first-class target for generated binding code. The JSON runtime is kept independent of net/http so it can be used on js/wasm toolchains where TinyGo's standard-library HTTP path is unavailable.

Verified with TinyGo 0.42.0 + Go 1.27.x.

./scripts/tinygo-check.sh
Runtime notes relevant to TinyGo
  • AsHTTPError avoids errors.As (unimplemented AssignableTo on some TinyGo builds).
  • WriteError hand-builds problem JSON (avoids fragile nested encoding/json + RawMessage interactions).
  • Registry uses reflect.Type only as a type identity key, not for field walking.
  • Generated bind/write code does not import reflect.
  • jsonbind parses and writes JSON itself and does not import encoding/json, so a JSON-only binary carries no reflection-based codec — around 40% of a tinygo build -target wasi binary, and about half of a -no-debug one. See Benchmarks.
  • Do not import encoding/json/v2 or jsontext into code a TinyGo build reaches. jsonbind never calls either, and the one place this repo does — internal/benchfixture, behind the tinybind_jsonv2bench build tag — measured a stripped wasi binary at 3.5× the size of the same program on jsonbind; see encoding/json/v2.
Known limitations
Topic Limitation
Toolchain Project baseline is TinyGo 0.42.0 + Go 1.27.x
js/wasm HTTP Builds on the current baseline; the net/http/roundtrip_js.go compile failure seen on TinyGo 0.41.1 + Go 1.26.x is gone. jsonbind is still the smaller choice for WASM code that needs no HTTP
Streaming Prefer host go test for WriteStream; not fully TinyGo-matrixed
ServeMux DefaultOptions discovers both net/http.ServeMux and tinygodriver/httpmux.ServeMux; use httpmux for Go 1.22 method and wildcard routing under TinyGo
Multipart File Supported via httpbind.File (payload); size/MIME check rules deferred. Body cap defaults to 1 MiB (SetMaxMultipartBodyBytes)
SQL mapping ScanRows and generated SQL scanners target host Go and are excluded from TinyGo builds
Generator Host-side only (go run / go test)

License

Licensed under the Apache License, Version 2.0.

Documentation

Overview

Package httpbind provides generated, reflection-free net/http request and response binding. Standalone JSON and SQL mapping live in the jsonbind and sqlbind packages so consumers do not compile unrelated platform dependencies.

Index

Constants

View Source
const (
	// StreamSSE is text/event-stream (data: <json>\n\n).
	StreamSSE = bindcore.StreamSSE
	// StreamNDJSON is application/x-ndjson (one JSON object per line).
	// Same family as JSONL / NDJSON; not a single JSON array document.
	StreamNDJSON = bindcore.StreamNDJSON
	// StreamJSONArray is application/json as one JSON array document:
	// [obj1,obj2,...] with items appended incrementally and closed by Close.
	StreamJSONArray = bindcore.StreamJSONArray
)
View Source
const DefaultActionSelectorField = "_action"

DefaultActionSelectorField is the hidden field a generated form carries to say which server function a native submit is for. It matches the template compiler's own default, and a project renaming one renames both.

View Source
const DefaultMaxCBORBodyBytes = bindcore.DefaultMaxCBORBodyBytes

DefaultMaxCBORBodyBytes is the default cap for CBOR body reads (1 MiB).

View Source
const DefaultMaxJSONBodyBytes = jsonbind.DefaultMaxJSONBodyBytes

DefaultMaxJSONBodyBytes is the default cap for JSON document reads (1 MiB).

View Source
const DefaultMaxMultipartBodyBytes = bindcore.DefaultMaxMultipartBodyBytes

DefaultMaxMultipartBodyBytes is the default cap on multipart request bodies enforced by ParseMultipartMap (1 MiB). Override with SetMaxMultipartBodyBytes. Without this, io.ReadAll / unrestricted ParseMultipartForm would accept arbitrarily large bodies inside tinybind-go alone.

View Source
const DefaultMultipartMaxMemory = bindcore.DefaultMultipartMaxMemory

DefaultMultipartMaxMemory is the maxMemory argument passed to http.Request.ParseMultipartForm (how much of the form stays in RAM before spilling file parts to temp files). This is not a body size cap; see DefaultMaxMultipartBodyBytes.

Variables

This section is empty.

Functions

func AcceptsCBOR added in v0.5.19

func AcceptsCBOR(r *http.Request) bool

AcceptsCBOR reports whether the client asked for a CBOR response. Only an explicit application/cbor entry in Accept counts; wildcards keep the JSON default, so a browser's */* never flips the response format.

func ActionSelector added in v0.5.8

func ActionSelector(r *http.Request, field string) string

ActionSelector returns the server function selector a native form submit carried, or the empty string when it carried none.

The query is read before the body because a submit button's formaction is what carries the selector when one form dispatches to several handlers, and that channel has to win over the form's own hidden field rather than merely coexist with it.

The value is compared as one opaque key by the caller, so no mismatch between the hash half and the name half is representable.

func AppendFileJSON added in v0.4.0

func AppendFileJSON(dst []byte, f File) []byte

AppendFileJSON appends an uploaded file the way encoding/json rendered it before generated encoders stopped going through reflection: exported fields in declaration order, with the content base64-encoded.

func AssembleOpenAPI added in v0.1.11

func AssembleOpenAPI() (jsonDoc []byte, err error)

AssembleOpenAPI merges every registered package fragment and returns a deterministic OpenAPI 3.1 JSON document.

func BadRequest

func BadRequest(problem Problem, cause ...error) error

BadRequest returns a 400 Bad Request error.

func Bind

func Bind[T any](r *http.Request) (T, error)

Bind maps an HTTP request into a typed request value. Dispatch uses a registry of generated binders; field mapping does not use reflect.

func BindError

func BindError(field, location, message string) error

BindError is returned when binding fails for a specific field/source.

func CheckDate

func CheckDate(s string) bool

CheckDate reports whether s is an ISO date (YYYY-MM-DD / time.DateOnly).

func CheckDateTime

func CheckDateTime(s string) bool

CheckDateTime reports whether s is RFC3339 (fractional seconds accepted).

func CheckEmail

func CheckEmail(s string) bool

CheckEmail reports whether s is a pragmatic (non-RFC5322) email. Empty string returns false; callers skip empty optional fields before calling.

func CheckTime

func CheckTime(s string) bool

CheckTime reports whether s is an ISO time (HH:MM:SS / time.TimeOnly).

func CheckUUID

func CheckUUID(s string) bool

CheckUUID reports whether s is a UUID string (8-4-4-4-12 hex with dashes).

func Conflict

func Conflict(problem Problem, cause ...error) error

Conflict returns a 409 Conflict error.

func CookieValue

func CookieValue(r *http.Request, name string) (string, bool)

CookieValue returns a cookie value if present.

func DispatchAction added in v0.5.8

func DispatchAction(w http.ResponseWriter, r *http.Request, handler http.HandlerFunc)

DispatchAction runs one server function on the page's own POST route and applies the post-redirect-get default.

A handler that writes nothing gets a 303 back to the page it was submitted from, so a reload does not resubmit and the address bar keeps showing the page. A handler that writes a status, a header, or a body keeps exactly that response, which is what lets it redirect elsewhere, render the page inline with validation errors, or stream.

The direct entry point of a server function adds no redirect: there the handler's output is the response verbatim. The two entry points therefore differ in what a silent handler means, which is deliberate and documented, because only the form entry point has a page to go back to.

func Forbidden

func Forbidden(problem Problem, cause ...error) error

Forbidden returns a 403 Forbidden error.

func FormLookup added in v0.5.34

func FormLookup(f FormValues, key string) (string, bool)

FormLookup returns the first value for key in a form body.

func HeaderValue

func HeaderValue(r *http.Request, key string) string

HeaderValue returns a request header.

func Internal

func Internal(err error) error

Internal returns a 500 Internal Server Error that wraps err.

func IsCBORRequest added in v0.5.19

func IsCBORRequest(r *http.Request) bool

IsCBORRequest reports whether the request body should be treated as CBOR. Matches application/cbor and *+cbor types (RFC 6839).

func IsJSONRequest

func IsJSONRequest(r *http.Request) bool

IsJSONRequest reports whether the request body should be treated as JSON. Matches application/json, text/json, and *+json types such as application/problem+json (RFC 7807 / RFC 9457).

func IsNormalClose added in v0.5.27

func IsNormalClose(err error) bool

IsNormalClose reports whether a socket error is the ordinary end of the connection — the peer's normal or going-away close, an already-sent close, or EOF — rather than a failure. A Read loop tests it to end quietly, and it answers the same on the fasthttp surface, where this driver's own IsCloseError would not recognize the other driver's CloseError.

func JSONBodyError added in v0.5.21

func JSONBodyError(err error) error

JSONBodyError wraps a structural JSON failure from a binder's inline body walk as a 400 problem.

func JSONBodyNotObject added in v0.5.21

func JSONBodyNotObject() error

JSONBodyNotObject is the 400 for a body that decodes to a non-object.

func MaxCBORBodyBytes added in v0.5.19

func MaxCBORBodyBytes() int64

MaxCBORBodyBytes returns the effective CBOR body limit.

func MaxJSONBodyBytes

func MaxJSONBodyBytes() int64

MaxJSONBodyBytes returns the effective JSON body limit.

func MaxMultipartBodyBytes

func MaxMultipartBodyBytes() int64

MaxMultipartBodyBytes returns the effective global multipart body limit.

func NotFound

func NotFound(problem Problem, cause ...error) error

NotFound returns a 404 Not Found error.

func OpenAPIDocument added in v0.5.2

func OpenAPIDocument() ([]byte, error)

OpenAPIDocument returns the assembled document, reusing the previous result until a fragment or info registration invalidates it.

It names no transport, so a second backend serves the document without reassembling it per request: a fragment registration cannot be observed from outside this package, which is what left a caller on another transport with AssembleOpenAPI and no way to cache the result itself.

The returned slice is shared with every other caller and must not be modified.

func OpenAPIJSON

func OpenAPIJSON(w http.ResponseWriter, r *http.Request)

OpenAPIJSON serves the assembled OpenAPI document as application/json.

func ParseBool

func ParseBool(s string) (bool, error)

ParseBool converts a string to bool.

func ParseBytes added in v0.5.24

func ParseBytes(s string) ([]byte, error)

ParseBytes decodes a base64 query, path, header or cookie value into a byte field. Both alphabets are accepted, padded or not, since a value that travelled through a URL may have been written either way; the encoder always produces padded standard base64.

func ParseFloat64

func ParseFloat64(s string) (float64, error)

ParseFloat64 converts a string to float64.

func ParseFormMap

func ParseFormMap(r *http.Request) (map[string]string, error)

ParseFormMap parses urlencoded form body into a flat map (first value wins).

func ParseInt

func ParseInt(s string) (int, error)

ParseInt converts a string to int.

func ParseInt64

func ParseInt64(s string) (int64, error)

ParseInt64 converts a string to int64.

func ParseIntBits added in v0.5.23

func ParseIntBits(s string, bits int) (int64, error)

ParseIntBits converts a string to a signed integer of the given width, reporting a value the width cannot hold rather than truncating it. bits is 0 for platform-width int.

The generated binder calls this for every signed width beside int and int64, which keep the two helpers they already had so their output does not move.

func ParseMultipartMap

func ParseMultipartMap(r *http.Request) (form map[string]string, files map[string]File, err error)

ParseMultipartMap parses a multipart/form-data body into scalar form fields (first value wins) and named file parts (first file wins per field name).

The request body is capped at MaxMultipartBodyBytes() so tinybind-go itself enforces a size limit (default 1 MiB): Content-Length is checked when known, r.Body is wrapped with http.MaxBytesReader, and per-file reads use LimitReader. Oversized bodies and oversize file parts map to HTTP 413.

func ParseUintBits added in v0.5.23

func ParseUintBits(s string, bits int) (uint64, error)

ParseUintBits is the unsigned twin of ParseIntBits. A leading minus is an error, so a negative query value cannot arrive as a large positive one.

func PathValue

func PathValue(r *http.Request, key string) string

PathValue returns the path value for key (Go 1.22+ ServeMux).

func PayloadTooLarge

func PayloadTooLarge(problem Problem, cause ...error) error

PayloadTooLarge returns a 413 Payload Too Large error.

func QueryLookup added in v0.4.3

func QueryLookup(q QueryValues, key string) (string, bool)

QueryLookup returns the first value for key from pre-parsed query values.

func QueryLookupAll added in v0.5.26

func QueryLookupAll(q QueryValues, key string) []string

QueryLookupAll returns every value for key, in the order the URL wrote them.

A repeated key is the array spelling a browser produces: an urlencoded form writes one pair per successful control, so a checkbox group named tag submits tag=a&tag=b. Nothing else is an array here — brackets are ordinary key characters, and a comma is an ordinary value character.

An empty value contributes nothing. A blank control submits its key with no value, so counting one would turn an untouched filter field into an element no user chose, and tag= and a bare tag are indistinguishable anyway.

func QueryValue

func QueryValue(r *http.Request, key string) (string, bool)

QueryValue returns the first query parameter value for key. It scans the raw query for that one key rather than materializing every pair the way r.URL.Query() would.

func ReadActionBody added in v0.5.10

func ReadActionBody(r *http.Request) ([]byte, error)

ReadActionBody reads the JSON payload of a typed server action call, under the configured body limit.

A generated wrapper calls this rather than reading the body itself, so the limit and the error mapping live in one place instead of being written into every emitted entry point.

func ReadCBORBody added in v0.5.19

func ReadCBORBody(r *http.Request) ([]byte, error)

ReadCBORBody reads the whole request body, bounded by MaxCBORBodyBytes. Decoding is the generated caller's: the bytes handed back are unparsed, and the decoder bounds its own walk by the same limit this read enforced.

func ReadJSONBody added in v0.5.21

func ReadJSONBody(r *http.Request) ([]byte, error)

ReadJSONBody reads the raw JSON body under MaxJSONBodyBytes. Generated binders parse the returned bytes in a single inline pass.

func ReadJSONBodyOwned added in v0.5.21

func ReadJSONBodyOwned(r *http.Request) ([]byte, error)

ReadJSONBodyOwned is ReadJSONBody under the name the transport pair needs: here the read buffer is always freshly owned, while the fasthttp runtime's version copies out of the pooled request. A binder that lets raw body bytes outlive the bind — a json.RawMessage field or rest map — is emitted against this name on both transports.

func Redirect added in v0.5.11

func Redirect(target string, status ...int) error

Redirect returns a value that sends the browser to target, travelling the error return because a caller returning values holds no ResponseWriter.

WriteError recognizes it and emits the status with a Location header instead of a problem document. The status defaults to 303; pass one of 301, 302, 307, or 308 to choose another.

It is an ordinary error value, so a page function, a handler, and a template's failing external all express a redirect the same way.

func RegisterBind

func RegisterBind[T any](fn func(*http.Request) (T, error))

RegisterBind registers a generated binder for T. Call from generated init(); field mapping lives entirely inside fn.

func RegisterOpenAPIFragment added in v0.1.11

func RegisterOpenAPIFragment(id string, jsonDoc []byte)

RegisterOpenAPIFragment registers a generated package fragment. ID should be the package import path. Assembly reports conflicting repeated IDs.

func RegisterOpenAPIFragmentString added in v0.4.3

func RegisterOpenAPIFragmentString(id string, jsonDoc string)

RegisterOpenAPIFragmentString is RegisterOpenAPIFragment for a string document. Generated code registers its embedded fragment constant through this so the constant is stored as-is, without a startup copy.

func RegisterWrite

func RegisterWrite[T any](fn func(http.ResponseWriter, *http.Request, T) error)

RegisterWrite registers a generated writer for T.

func ResetOpenAPIFragments added in v0.1.11

func ResetOpenAPIFragments()

ResetOpenAPIFragments clears registered fragments. It is intended for tests.

func RestFormAny

func RestFormAny(formBody FormValues, exclude []string) map[string]any

RestFormAny builds map[string]any from the form keys not in exclude (string values).

func RestFormRaw

func RestFormRaw(formBody FormValues, exclude []string) map[string]json.RawMessage

RestFormRaw builds map[string]json.RawMessage from the form keys not in exclude (JSON-encoded strings).

func SetMaxCBORBodyBytes added in v0.5.19

func SetMaxCBORBodyBytes(n int64)

SetMaxCBORBodyBytes changes the process-wide CBOR body limit. A non-positive value restores DefaultMaxCBORBodyBytes. Both transport runtimes honour the same value.

func SetMaxJSONBodyBytes

func SetMaxJSONBodyBytes(n int64)

SetMaxJSONBodyBytes changes the process-wide JSON body limit. A non-positive value restores DefaultMaxJSONBodyBytes.

func SetMaxMultipartBodyBytes

func SetMaxMultipartBodyBytes(n int64)

SetMaxMultipartBodyBytes sets the global multipart body size limit used by ParseMultipartMap (and generated binders). The limit wraps r.Body with http.MaxBytesReader and bounds per-file reads.

The value lives in bindcore, so a process setting it once configures every transport runtime rather than only the one it happened to call.

n > 0  → use n bytes
n <= 0 → restore DefaultMaxMultipartBodyBytes (1 MiB)

func SetOpenAPIInfo added in v0.1.11

func SetOpenAPIInfo(info OpenAPIInfo) error

SetOpenAPIInfo sets application-level metadata for the assembled document. Repeating the same value is harmless; a different second value is an error.

func SetSocketDefaults added in v0.5.4

func SetSocketDefaults(opts SocketOptions)

SetSocketDefaults installs the process-wide socket options. It is shared with the fasthttp runtime, so installing them once covers both.

func SetStreamErrorHandler added in v0.4.9

func SetStreamErrorHandler(fn func(error))

SetStreamErrorHandler installs the destination for stream failures that happen after the response status has been sent. Passing nil discards them, which is the default: a runtime that logged on its own would be writing to a destination the caller did not choose.

The handler is shared with the fasthttp runtime, so installing it once covers both.

func SwaggerUI

func SwaggerUI(specURL string) http.Handler

SwaggerUI returns an http.Handler that serves a minimal Swagger UI page loading the OpenAPI document from specURL (e.g. "/openapi.json").

Assets are loaded from a public CDN; this handler does not embed Swagger UI binaries. Mount freely, e.g.:

mux.Handle("GET /docs/{$}", httpbind.SwaggerUI("/openapi.json"))

func Unauthorized

func Unauthorized(problem Problem, cause ...error) error

Unauthorized returns a 401 Unauthorized error.

func Validation

func Validation(fields ...FieldError) error

Validation returns a 400 Bad Request validation error with field details.

func VaryAccept added in v0.5.20

func VaryAccept(w http.ResponseWriter)

VaryAccept records that the response body depends on the Accept header, so a shared cache keys the entry on it. Generated writers call it before negotiating; without it a cache could hand a CBOR body to a JSON client.

func WebSocket added in v0.5.4

func WebSocket[In, Out any](w http.ResponseWriter, r *http.Request, fn func(*Socket[In, Out]) error) error

WebSocket upgrades the request, runs fn against a typed socket, and closes the socket when fn returns.

Handler usage:

_ = httpbind.WebSocket(w, r, func(s *httpbind.Socket[ClientMsg, ServerMsg]) error {
	for {
		in, err := s.Read()
		if err != nil {
			return err
		}
		if err := s.Write(ServerMsg{Type: "echo", Text: in.Text}); err != nil {
			return err
		}
	}
})

The return value is the handshake error and nothing else. A non-nil value means the refusal response has already been written, as RFC 9457 Problem Details; the handler logs or counts it rather than answering. fn's own error is raised after the 101 has gone out, on this transport and on fasthttp, so it reaches the handler installed with SetStreamErrorHandler instead.

fn runs before this returns here and after the handler returns on fasthttp. Nothing in the callback may read the request, so that one source works on both: capture what it needs — the identity, the peer — before calling.

func WebSocketWith added in v0.5.4

func WebSocketWith[In, Out any](w http.ResponseWriter, r *http.Request, opts SocketOptions, fn func(*Socket[In, Out]) error) error

WebSocketWith is WebSocket with per-call options, for the endpoint whose limits or cadence differ from the process defaults.

func Write

func Write[T any](w http.ResponseWriter, r *http.Request, value T) error

Write serializes a typed response value to the HTTP response via a registered writer, or, for a type carrying its own encoder, through jsonbind.Appender. Status is always 200 OK; use WriteStatus for other success codes.

The interface is tried first, for the reason jsonbind.EncodeJSON states: a type that carries a method has an author-written encoder, and going through a generated one instead would produce bytes they did not intend. It is also what lets a value from a package this build never analyzed be answered with at all, which no registration could reach.

func WriteCBORBytes added in v0.5.19

func WriteCBORBytes(w http.ResponseWriter, status int, data []byte) error

WriteCBORBytes writes an already-encoded CBOR document, the WriteJSONBytes twin. Generated writers build the body into a pooled buffer and hand it over here.

func WriteError

func WriteError(w http.ResponseWriter, r *http.Request, err error)

WriteError writes err as an RFC 9457 Problem Details response. Internal causes are not exposed in the client body.

JSON is written without encoding/json for the problem document, so the runtime links no reflection-driven encoder for it. The document itself is derived in bindcore, so the other transport runtime writes the same bytes for the same error rather than reimplementing the rule.

func WriteJSONBytes added in v0.4.0

func WriteJSONBytes(w http.ResponseWriter, status int, data []byte) error

WriteJSONBytes writes an already-encoded document. Generated writers build the body into a pooled buffer and hand it over here, so the response path never reflects over the value and never allocates an intermediate map.

func WriteStatus

func WriteStatus[T any](w http.ResponseWriter, r *http.Request, status int, value T) error

WriteStatus serializes value with an explicit HTTP status code using the registered encoder for T (no field-walking reflection on T). For status 204 No Content, the body is not written.

func WriteStream added in v0.4.9

func WriteStream[T any](w http.ResponseWriter, r *http.Request, fn func(*Stream[T]) error)

WriteStream opens a negotiated stream, runs fn against it, and closes it.

It returns nothing. fn runs after the handler has returned on the fasthttp runtime, where an error cannot travel back to handler code, so neither surface offers one and the same handler source works on both.

A failure to open — before any byte is committed — becomes an ordinary Problem response. Once the stream is open the status is already sent, so an error from fn reaches the handler installed with SetStreamErrorHandler instead. Close runs either way, which is what keeps a JSON array document terminated when fn fails halfway through it.

Types

type Declaration added in v0.5.10

type Declaration struct{}

Declaration is what ServerAction returns. It carries nothing: the value exists only so the annotation can be written as a package-level declaration, which is where generation reads it.

func ServerAction added in v0.5.10

func ServerAction(fn any, name ...string) Declaration

ServerAction declares that fn is a server action reachable from client script, whatever its signature.

A handler-shaped function is an action by existing, because that shape is unambiguous: an exported function taking the transport types and returning nothing is nothing else. An arbitrary signature distinguishes nothing, since every function has one, so something outside the signature has to say which functions are actions. That is what this declaration is for, and it is the only thing it does.

Write it at package level, beside the function:

var _ = httpbind.ServerAction(GetUser)

fn is taken as a symbol rather than as a name string, so a declaration naming something that does not exist fails to compile before generation reads it.

The optional name is the identifier client script calls through. Without one it is derived from the Go name in initialism-aware lowerCamelCase, so GetUser is reached as getUser and URLFor as urlFor. Supply one for a name the derivation reads wrong, or for a published name a Go rename must not move: like a struct tag, it is a wire name rather than a second identity.

The call runs at init and does nothing. The declaration is the point.

type FieldError

type FieldError = bindcore.FieldError

FieldError describes a single field-level validation failure.

func Field

func Field(field, location, message string) FieldError

Field builds a field-level validation error.

type File

type File = bindcore.File

File is an uploaded file bound from a multipart/form-data part. After a successful bind, Filename, ContentType (when the client sent one), Size, and Content are populated from the named file part.

It is an alias so a model struct declaring a File field compiles against either transport runtime without naming one of them.

type FormValues added in v0.5.34

type FormValues = bindcore.FormValues

FormValues is a form body read once; see bindcore.FormValues. Generated binders ask it for their fields through FormLookup.

func ReadFormBody added in v0.5.21

func ReadFormBody(r *http.Request, wantForm, wantFiles bool) (FormValues, map[string]File, error)

ReadFormBody dispatches on the form content types alone, for binders that read their JSON body inline through ReadJSONBody.

An urlencoded body is read once and split into key=value spans, unescaped only where a field is looked up, rather than parsed into url.Values and copied into a map: the same trade the query string makes. A multipart body goes through net/http's parser and keeps the map it built.

type HTTPError

type HTTPError = bindcore.HTTPError

HTTPError is an HTTP-mapped error with optional RFC 9457 details and cause.

func AsHTTPError

func AsHTTPError(err error) (*HTTPError, bool)

AsHTTPError extracts *HTTPError from err if present.

type OpenAPIInfo added in v0.1.11

type OpenAPIInfo struct {
	Title   string
	Version string
}

OpenAPIInfo is application-owned metadata for the assembled document.

type Problem

type Problem = bindcore.Problem

Problem is an application error payload carried by status helpers.

type QueryValues added in v0.5.21

type QueryValues = bindcore.QueryValues

QueryValues is the request's query string split once into raw key=value spans, in wire order.

It is an alias, like the error model and File, so the value a binder holds is the same type on either transport runtime and the lookups below cannot drift from the fasthttp ones.

func Queries added in v0.4.3

func Queries(r *http.Request) QueryValues

Queries parses the request's query string once. Generated binders call this a single time per request and resolve each field with QueryLookup, instead of re-parsing the raw query per field the way QueryValue does.

type Socket added in v0.5.4

type Socket[In, Out any] = bindcore.Socket[In, Out]

Socket is a typed WebSocket connection: Read decodes into In, Write encodes from Out, both through the jsonbind codec registry.

It is the same type the fasthttp runtime uses, so a callback body compiles unchanged on either transport. In and Out must each have a generated codec — a decoder for In, an encoder for Out — which discovery emits from the two type arguments of the WebSocket call.

Read must be called from one goroutine. Write may be called from any.

type SocketOptions added in v0.5.4

type SocketOptions = bindcore.SocketOptions

SocketOptions configures one socket. A zero field takes the process default installed with SetSocketDefaults, and nothing reaches the driver as zero.

func SocketDefaults added in v0.5.4

func SocketDefaults() SocketOptions

SocketDefaults returns the effective process defaults.

type Stream

type Stream[T any] = bindcore.Stream[T]

Stream is a typed incremental response stream.

Handler usage:

httpbind.WriteStream(w, r, func(s *httpbind.Stream[ChatEvent]) error {
	if err := s.Write(ChatEvent{Type: "delta", Delta: "hi"}); err != nil {
		return err
	}
	return s.Write(ChatEvent{Type: "done"})
})

Format (SSE vs NDJSON vs JSON array) is chosen once by rule:stream-content-negotiation. Write may be called many times; headers and status are sent when the stream opens. WriteStream closes the stream, which is what writes the trailing ']' of the JSON array framing.

The framing lives in one place shared with the fasthttp runtime, so the same events produce the same bytes on either transport.

Events are encoded through the jsonbind codec registry: T must have a generated encoder (or one registered manually via jsonbind.RegisterEncode).

type StreamFormat

type StreamFormat = bindcore.StreamFormat

StreamFormat is the negotiated on-the-wire format for Stream[T].

func NegotiateStreamFormat

func NegotiateStreamFormat(r *http.Request) StreamFormat

NegotiateStreamFormat selects SSE, NDJSON, or JSON array using:

  1. ?stream= query
  2. Accept
  3. User-Agent heuristics
  4. default NDJSON

Exported for tests and advanced callers.

Directories

Path Synopsis
Package cachekeybind provides typed, reflection-free cache key generation.
Package cachekeybind provides typed, reflection-free cache key generation.
Package cborbind generates CBOR codecs for the types its entry points name.
Package cborbind generates CBOR codecs for the types its entry points name.
Package cliparser parses argv into a map of stable config keys using precomputed flag definitions.
Package cliparser parses argv into a map of stable config keys using precomputed flag definitions.
cmd
tinybind-gen command
Package configbind loads Bind-style config from defaults, TOML, env, and CLI into structs.
Package configbind loads Bind-style config from defaults, TOML, env, and CLI into structs.
codegen
Package codegen emits reflection-free configbind apply, flag, and env key tables.
Package codegen emits reflection-free configbind apply, flag, and env key tables.
Package configpath resolves one config file path for configbind.
Package configpath resolves one config file path for configbind.
Package dynamobind provides typed, reflection-free DynamoDB item binding on top of github.com/shibukawa/tinygodriver/nosql/dynamodb.
Package dynamobind provides typed, reflection-free DynamoDB item binding on top of github.com/shibukawa/tinygodriver/nosql/dynamodb.
examples
demo command
websocket command
Command websocket serves a typed WebSocket chat room beside ordinary REST routes on one port, under both compilers.
Command websocket serves a typed WebSocket chat room beside ordinary REST routes on one port, under both compilers.
Package fasthttpbind is the fasthttp half of the binding runtime.
Package fasthttpbind is the fasthttp half of the binding runtime.
Package fasthttpupdate is the fasthttp half of the partial-update surface.
Package fasthttpupdate is the fasthttp half of the partial-update surface.
Package firestorebind provides typed, reflection-free entity binding for Firestore in Datastore mode, on top of github.com/shibukawa/tinygodriver/nosql/datastore.
Package firestorebind provides typed, reflection-free entity binding for Firestore in Datastore mode, on top of github.com/shibukawa/tinygodriver/nosql/datastore.
Package htmlbind is the rendering runtime for generated HTML templates.
Package htmlbind is the rendering runtime for generated HTML templates.
delta
Package delta compares two renders of one chain and expresses the difference as operations a browser applies, so a screen already showing the document reaches the server's fresh render without a full page load.
Package delta compares two renders of one chain and expresses the difference as operations a browser applies, so a screen already showing the document reaches the server's fresh render without a full page load.
Package htmlupdate serves HTML templates that can update themselves in place.
Package htmlupdate serves HTML templates that can update themselves in place.
internal
benchfixture
Package benchfixture backs the benchmark table in the project README.
Package benchfixture backs the benchmark table in the project README.
bindcore
Package bindcore holds the declarations both transport runtimes need and neither should own: the error model, the uploaded-file value, and the check helpers.
Package bindcore holds the declarations both transport runtimes need and neither should own: the error model, the uploaded-file value, and the check helpers.
dynamofixture
Package dynamofixture exercises the generated DynamoDB item codec against the dynamobind runtime and the driver's wire protocol.
Package dynamofixture exercises the generated DynamoDB item codec against the dynamobind runtime and the driver's wire protocol.
externalscan
Package externalscan reads the Go signatures of the package-level functions a template may call as externals, and reports the two things generation cannot learn from the template: which take a leading context.Context, and which return a trailing error.
Package externalscan reads the Go signatures of the package-level functions a template may call as externals, and reports the two things generation cannot learn from the template: which take a leading context.Context, and which return a trailing error.
fasthttppagesfixture/pages/raw
Package raw is the rung 3 route: a page whose Load owns the whole response.
Package raw is the rung 3 route: a page whose Load owns the whole response.
firestorefixture
Package firestorefixture exercises the generated Firestore entity codec against the firestorebind runtime and the driver's wire protocol.
Package firestorefixture exercises the generated Firestore entity codec against the firestorebind runtime and the driver's wire protocol.
gensource
Package gensource identifies the Go files a generation run wrote.
Package gensource identifies the Go files a generation run wrote.
godoc
Package godoc extracts documentation text from Go doc comments so host-side analysis can carry it into generated artifacts such as OpenAPI descriptions.
Package godoc extracts documentation text from Go doc comments so host-side analysis can carry it into generated artifacts such as OpenAPI descriptions.
linedirective
Package linedirective builds the Go //line comments that map generated template code back to the template that produced it.
Package linedirective builds the Go //line comments that map generated template code back to the template that produced it.
pagesfixture/pages/archive
Package archive is the route that needs the request itself rather than the address it was sent to.
Package archive is the route that needs the request itself rather than the address it was sent to.
pagesfixture/pages/records/id_
Package id_ serves one record with no typed entry point.
Package id_ serves one record with no typed entry point.
updatecore
Package updatecore is the transport-free half of the partial-update surface.
Package updatecore is the transport-free half of the partial-update surface.
Package jsonbind provides generated, reflection-free JSON document codecs.
Package jsonbind provides generated, reflection-free JSON document codecs.
Package minitoml parses a restricted TOML subset into a flat intermediate key/value form.
Package minitoml parses a restricted TOML subset into a flat intermediate key/value form.
codegen
Package codegen emits reflection-free apply functions from intermediate minitoml.Document keys.
Package codegen emits reflection-free apply functions from intermediate minitoml.Document keys.
Package routetree discovers a filesystem route tree and derives the stdlib ServeMux patterns, ancestor layout chains, and Go package names for it.
Package routetree discovers a filesystem route tree and derives the stdlib ServeMux patterns, ancestor layout chains, and Go package names for it.
Package sqlbind provides generated, reflection-free database/sql row mapping.
Package sqlbind provides generated, reflection-free database/sql row mapping.
templates
dynamobind
Package dynamobind parses and prints typed DynamoDB access-pattern sources.
Package dynamobind parses and prints typed DynamoDB access-pattern sources.
firestorebind
Package firestorebind parses and prints typed Firestore Datastore access-pattern sources.
Package firestorebind parses and prints typed Firestore Datastore access-pattern sources.
htmlbind
Package htmlbind parses typed HTML template sources into an AST.
Package htmlbind parses typed HTML template sources into an AST.
internal/rawparse
Package rawparse provides the lossless dummy format parser used to exercise the shared template parser without HTML or SQL knowledge.
Package rawparse provides the lossless dummy format parser used to exercise the shared template parser without HTML or SQL knowledge.
sqlbind
Package sqlbind parses and compiles typed SQL template sources.
Package sqlbind parses and compiles typed SQL template sources.
templatefmt
Package templatefmt formats tinybind template sources.
Package templatefmt formats tinybind template sources.
Package tomlbind decodes one TOML document into a struct through generated code, and imports nothing of configbind.
Package tomlbind decodes one TOML document into a struct through generated code, and imports nothing of configbind.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL