httpbinder

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

httpbind-go (httpbinder)

日本語

Reflection-free, code-generation-first library that bridges Go types and HTTP APIs.

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, kept in sync with binders and writers. 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 := httpbinder.Bind[CreateUserRequest](r)
	if err != nil {
		httpbinder.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,
	}
	_ = httpbinder.Write[CreateUserResponse](w, r, out)
}

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

go run ./cmd/httpbinder-gen -dir . -openapi
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 httpbinder.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 httpbinder.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)
stream, err := httpbinder.NewStream[ChatEvent](w, r)
if err != nil {
    httpbinder.WriteError(w, r, err)
    return
}
defer stream.Close()

_ = stream.Write(ChatEvent{Type: "delta", Delta: "hi"})
_ = stream.Write(ChatEvent{Type: "done"})
  • Write can be called many times (incremental events).
  • Format is chosen once in NewStream from ?stream=, Accept, User-Agent, then default NDJSON.
  • Formats:
    • SSEtext/event-stream
    • NDJSON / JSONLapplication/x-ndjson (one object per line; not a JSON array)
    • JSON arrayapplication/json as [obj1,obj2,...] (Close writes the trailing ])
  • Do not use removed helpers WriteNDJSON / WriteSSE.

Packages

Path Role
. (package httpbinder) Runtime: Bind / Write / WriteError / NewStream / OpenAPI serve / SwaggerUI
generator/ Field-plan binders/writers + OpenAPI 3.1 embed generation
parser/ Route/handler discovery (Bind, Write, NewStream, errors)
cmd/httpbinder-gen CLI: binders + OpenAPI 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/httpbinder-gen -dir ./path/to/package

Custom generator commands only need to call generator.Main. Start with DefaultOptions, then replace each authoritative Set with every identity the project accepts:

package main

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

func main() {
    options := generator.DefaultOptions()
    options.ServeMuxes.Set = []generator.TypePattern{
        {PackagePath: "net/http", Name: "ServeMux"},
        {PackagePath: "github.com/shibukawa/petitweb-go/handler", Name: "ServeMux"},
    }
    options.RuntimePackages.Set = []string{
        "github.com/shibukawa/httpbind-go",
        "github.com/shibukawa/petitweb-go/handler",
    }
    generator.Main(options)
}

RuntimePackages expands the same-named Bind, Write, WriteStatus, DecodeJSON, EncodeJSON, NewStream, and ScanRows functions. An operation-specific set such as options.DecodeJSON.Set replaces that expansion. Set always replaces defaults; include both the standard and compatibility identity when both should be explored. generator.Options{} deliberately has no discovery identities. Set a pattern's Disabled field, or add its feature to DisableFeatures, to prevent discovery even under -generate-all.

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

JSON reads are capped at 1 MiB by default. Use SetMaxJSONBodyBytes globally or DecodeJSONLimit per call. Oversize input returns HTTP 413.

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 := httpbinder.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.

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   NewStream (SSE / NDJSON / JSON array auto)

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

TinyGo

TinyGo is a design goal for the reflection-free binder path. See notes below for toolchain limits.

Verified with TinyGo 0.41.1 + Go 1.26.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.
Known limitations
Topic Limitation
Toolchain Project baseline is TinyGo 0.41.1 + Go 1.26.x
Streaming Prefer host go test for NewStream; not fully TinyGo-matrixed
ServeMux Prefer testing handlers with ServeHTTP + SetPathValue under TinyGo
Multipart File Supported via httpbinder.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

Index

Constants

View Source
const DefaultMaxJSONBodyBytes int64 = 1 << 20

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

View Source
const DefaultMaxMultipartBodyBytes int64 = 1 << 20

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 httpbind-go alone.

View Source
const DefaultMultipartMaxMemory int64 = 32 << 20

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 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 BytesJSONMap added in v0.1.2

func BytesJSONMap(data []byte) (map[string]json.RawMessage, error)

BytesJSONMap decodes a full JSON document (bytes) as an object map.

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 (or RFC3339Nano on failure).

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). Version/variant bits are not enforced.

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 DecodeJSON added in v0.1.2

func DecodeJSON[T any](r io.Reader) (T, error)

DecodeJSON decodes one JSON value from r into T using a generated codec. It does not inspect HTTP headers or use reflection on T's fields.

func DecodeJSONBool

func DecodeJSONBool(raw json.RawMessage) (bool, error)

DecodeJSONBool unmarshals a JSON raw value as bool.

func DecodeJSONBoolSlice added in v0.1.2

func DecodeJSONBoolSlice(raw json.RawMessage) ([]bool, error)

DecodeJSONBoolSlice decodes a JSON array of bools.

func DecodeJSONFloat64

func DecodeJSONFloat64(raw json.RawMessage) (float64, error)

DecodeJSONFloat64 unmarshals a JSON raw value as float64.

func DecodeJSONFloat64Slice added in v0.1.2

func DecodeJSONFloat64Slice(raw json.RawMessage) ([]float64, error)

DecodeJSONFloat64Slice decodes a JSON array of float64.

func DecodeJSONInt

func DecodeJSONInt(raw json.RawMessage) (int, error)

DecodeJSONInt unmarshals a JSON raw value as int.

func DecodeJSONInt64

func DecodeJSONInt64(raw json.RawMessage) (int64, error)

DecodeJSONInt64 unmarshals a JSON raw value as int64.

func DecodeJSONInt64Slice added in v0.1.2

func DecodeJSONInt64Slice(raw json.RawMessage) ([]int64, error)

DecodeJSONInt64Slice decodes a JSON array of int64.

func DecodeJSONIntSlice added in v0.1.2

func DecodeJSONIntSlice(raw json.RawMessage) ([]int, error)

DecodeJSONIntSlice decodes a JSON array of ints.

func DecodeJSONLimit added in v0.1.3

func DecodeJSONLimit[T any](r io.Reader, limit int64) (T, error)

DecodeJSONLimit is DecodeJSON with a per-call byte limit. A non-positive limit uses MaxJSONBodyBytes.

func DecodeJSONMapStringString added in v0.1.2

func DecodeJSONMapStringString(raw json.RawMessage) (map[string]string, error)

DecodeJSONMapStringString decodes a JSON object with string values.

func DecodeJSONString

func DecodeJSONString(raw json.RawMessage) (string, error)

DecodeJSONString unmarshals a JSON raw value as string.

func DecodeJSONStringSlice added in v0.1.2

func DecodeJSONStringSlice(raw json.RawMessage) ([]string, error)

DecodeJSONStringSlice decodes a JSON array of strings.

func EncodeJSON added in v0.1.2

func EncodeJSON[T any](w io.Writer, v T) error

EncodeJSON encodes v as compact JSON to w using a generated codec. It does not set HTTP headers or status.

func Forbidden

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

Forbidden returns a 403 Forbidden error.

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 IsFormRequest

func IsFormRequest(r *http.Request) bool

IsFormRequest reports application/x-www-form-urlencoded.

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 IsMultipartRequest

func IsMultipartRequest(r *http.Request) bool

IsMultipartRequest reports multipart/form-data.

func MaxJSONBodyBytes added in v0.1.3

func MaxJSONBodyBytes() int64

MaxJSONBodyBytes returns the effective JSON body limit.

func MaxMultipartBodyBytes added in v0.1.2

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 OpenAPIDocumentJSON

func OpenAPIDocumentJSON() []byte

OpenAPIDocumentJSON returns the registered OpenAPI JSON document (copy).

func OpenAPIDocumentYAML

func OpenAPIDocumentYAML() []byte

OpenAPIDocumentYAML returns the registered OpenAPI YAML document (copy).

func OpenAPIJSON

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

OpenAPIJSON serves the embedded OpenAPI document as application/json.

func OpenAPIYAML

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

OpenAPIYAML serves the embedded OpenAPI document as application/yaml.

func ParseBool

func ParseBool(s string) (bool, error)

ParseBool converts a string to bool.

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 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 httpbind-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 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 QueryValue

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

QueryValue returns the first query parameter value for key.

func RawJSONArray added in v0.1.2

func RawJSONArray(raw json.RawMessage) ([]json.RawMessage, error)

RawJSONArray decodes a JSON array RawMessage into element raw values.

func RawJSONMap added in v0.1.2

func RawJSONMap(raw json.RawMessage) (map[string]json.RawMessage, error)

RawJSONMap decodes a JSON object RawMessage into a map of raw fields.

func ReadJSONMap

func ReadJSONMap(r *http.Request) (map[string]json.RawMessage, error)

ReadJSONMap decodes a JSON object body into a map of raw messages. Used by generated binders so they can pick named fields without reflect on T. Non-object JSON (arrays, scalars) fails with 400 — required when payload:"*" rest maps are used.

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 RegisterDecode added in v0.1.2

func RegisterDecode[T any](fn func([]byte) (T, error))

RegisterDecode registers a generated JSON decoder for T (document only).

func RegisterEncode added in v0.1.2

func RegisterEncode[T any](fn func(io.Writer, T) error)

RegisterEncode registers a generated compact JSON encoder for T.

func RegisterOpenAPI

func RegisterOpenAPI(jsonDoc, yamlDoc []byte)

RegisterOpenAPI stores generated OpenAPI document bytes for OpenAPIJSON/OpenAPIYAML. Called from generated init(); not a handwritten OpenAPI source of truth.

func RegisterScanRows added in v0.1.3

func RegisterScanRows[T any](fn func(*sql.Rows) ([]T, error))

RegisterScanRows registers a generated SQL tree scanner for T.

func RegisterWrite

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

RegisterWrite registers a generated writer for T.

func RestFormAny added in v0.1.2

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

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

func RestFormRaw added in v0.1.2

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

RestFormRaw builds map[string]json.RawMessage from leftover form keys (JSON-encoded strings).

func RestJSONAny added in v0.1.2

func RestJSONAny(jsonBody map[string]json.RawMessage, exclude []string) (map[string]any, error)

RestJSONAny builds map[string]any from leftover JSON object keys not in exclude. Nested JSON values are decoded into any (objects/arrays/numbers/bools/strings/null). Prefer non-nil empty map when nothing remains.

func RestJSONRaw added in v0.1.2

func RestJSONRaw(jsonBody map[string]json.RawMessage, exclude []string) map[string]json.RawMessage

RestJSONRaw builds map[string]json.RawMessage from leftover JSON object keys not in exclude.

func ScanRows added in v0.1.3

func ScanRows[T any](rows *sql.Rows) ([]T, error)

ScanRows maps joined SQL rows into a grouped object tree using generated code.

func SetMaxJSONBodyBytes added in v0.1.3

func SetMaxJSONBodyBytes(n int64)

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

func SetMaxMultipartBodyBytes added in v0.1.2

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.

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

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/{$}", httpbinder.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 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. Status is always 200 OK; use WriteStatus for other success codes.

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 TinyGo does not hit unimplemented reflect.AssignableTo when binders also use json.RawMessage (a known interaction in TinyGo's encoding/json).

func WriteJSON

func WriteJSON(w http.ResponseWriter, status int, v any) error

WriteJSON is a helper for generated writers: encode a pre-built map/slice without reflecting over application structs. Content-Type is application/json.

func WriteStatus added in v0.1.3

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.

Types

type FieldError

type FieldError struct {
	Field    string
	Location string
	Message  string
}

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 struct {
	Filename    string
	ContentType string
	Size        int64
	Content     []byte
}

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.

func (File) Empty

func (f File) Empty() bool

Empty reports whether f has no filename and no content.

type HTTPError

type HTTPError struct {
	Status  int
	Title   string
	Problem Problem
	Fields  []FieldError
	// contains filtered or unexported fields
}

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. Implemented without errors.As so TinyGo does not require reflect.AssignableTo (unimplemented for interfaces in TinyGo 0.40), which otherwise panics when Bind's json.RawMessage path is also linked into the same binary.

func (*HTTPError) Error

func (e *HTTPError) Error() string

func (*HTTPError) Unwrap

func (e *HTTPError) Unwrap() error

type Problem

type Problem struct {
	Code    string
	Message string
}

Problem is an application error payload carried by status helpers.

type Stream

type Stream[T any] struct {
	// contains filtered or unexported fields
}

Stream is a typed incremental response stream.

Ideal handler usage:

stream, err := httpbinder.NewStream[ChatEvent](w, r)
if err != nil { ... }
defer stream.Close()
_ = stream.Write(ChatEvent{Type: "delta", Delta: "hi"})
_ = stream.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/status are sent only in NewStream. JSON array framing requires Close (via defer) so the trailing ']' is written.

func NewStream

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

NewStream negotiates transport format from the request, writes response headers and 200 once, and returns a stream for incremental Write calls.

func (*Stream[T]) Close

func (s *Stream[T]) Close() error

Close marks the stream finished. Idempotent. For JSON array format, Close writes the trailing ']' (or "[]" if no Write). SSE and NDJSON do not require a special trailer; still call Close for symmetry.

func (*Stream[T]) Format

func (s *Stream[T]) Format() StreamFormat

Format returns the negotiated stream format (sse | ndjson | json-array).

func (*Stream[T]) Write

func (s *Stream[T]) Write(v T) error

Write encodes one event in the negotiated format. Callable many times; does not re-send HTTP status or headers.

type StreamFormat

type StreamFormat string

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

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

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.

Note: NDJSON/JSONL (line-delimited objects) is distinct from JSON array (a single [...] document). application/json selects the array form; application/x-ndjson / application/jsonl select NDJSON.

Directories

Path Synopsis
cmd
httpbinder-gen command
examples
demo command
internal
Package sqlmap contains reflection-free primitives used by generated SQL scanners.
Package sqlmap contains reflection-free primitives used by generated SQL scanners.

Jump to

Keyboard shortcuts

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