bindcore

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package bindcore holds the declarations both transport runtimes need and neither should own: the error model, the uploaded-file value, and the check helpers. Keeping them here is what lets an error cross between the net/http and fasthttp surfaces and still match, and what keeps a model struct naming File from pulling a transport in behind it.

It imports no transport package.

Index

Constants

View Source
const DefaultMaxMultipartBodyBytes int64 = 1 << 20

DefaultMaxMultipartBodyBytes is the default cap on multipart request bodies (1 MiB). Override with SetMaxMultipartBodyBytes.

View Source
const DefaultMultipartMaxMemory int64 = 32 << 20

DefaultMultipartMaxMemory is how much of a multipart form stays in RAM before file parts spill to temp files. This is not a body size cap; see DefaultMaxMultipartBodyBytes.

View Source
const ProblemContentType = "application/problem+json"

ProblemContentType is the media type of an RFC 9457 error document.

Variables

View Source
var (
	ErrNilStream    = errors.New("httpbind: nil stream")
	ErrStreamClosed = errors.New("httpbind: stream closed")
)
View Source
var ErrFileTooLarge = errors.New("httpbind: multipart file too large")

ErrFileTooLarge is returned when a single file part exceeds the limit.

Functions

func AppendFileJSON

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 BadRequest

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

BadRequest returns a 400 Bad Request error.

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

func Conflict

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

Conflict returns a 409 Conflict error.

func Forbidden

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

Forbidden returns a 403 Forbidden error.

func Internal

func Internal(err error) error

Internal returns a 500 Internal Server Error that wraps err.

func IsJSONMediaType

func IsJSONMediaType(media string) bool

IsJSONMediaType reports whether media is JSON or a +json structured syntax suffix type (RFC 6839), e.g. application/json, application/problem+json, application/vnd.api+json. text/json is also accepted.

func IsMessageTooLarge

func IsMessageTooLarge(err error) bool

IsMessageTooLarge reports the transport-neutral size-limit failures, without errors.As so TinyGo does not need reflect.AssignableTo. A caller adds its own transport's error type before consulting this.

func MaxMultipartBodyBytes

func MaxMultipartBodyBytes() int64

MaxMultipartBodyBytes returns the effective global multipart body limit.

func MediaType

func MediaType(ct string) string

MediaType returns the lowercase type/subtype of a Content-Type header value (parameters after ';' are stripped).

func MultipartParseError

func MultipartParseError(err error, tooLarge bool) error

MultipartParseError maps a parse failure to 413 or 400. The caller decides tooLarge, because detecting it needs a transport-specific error type on top of the shared cases IsMessageTooLarge covers.

func NotFound

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

NotFound returns a 404 Not Found error.

func PayloadTooLarge

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

PayloadTooLarge returns a 413 Payload Too Large error.

func ProblemResponse

func ProblemResponse(err error) (status int, body []byte, ok bool)

ProblemResponse derives the status and body of the RFC 9457 document for err. ok is false when err is nil and nothing should be written.

Both transport runtimes call this rather than deriving the document themselves, which is what makes their error bytes identical by construction instead of by two implementations agreeing.

func ReportStreamError

func ReportStreamError(err error)

ReportStreamError hands err to the installed handler, if any.

func RestFormAny

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

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

func RestFormRaw

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

RestFormRaw builds map[string]json.RawMessage from leftover form keys.

func SetMaxMultipartBodyBytes

func SetMaxMultipartBodyBytes(n int64)

SetMaxMultipartBodyBytes sets the global multipart body size limit.

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

func SetStreamErrorHandler

func SetStreamErrorHandler(fn func(error))

SetStreamErrorHandler installs the destination for post-commit stream failures. Passing nil discards them, which is the default: a runtime logging on its own would write to a destination the caller did not choose.

func StatusText

func StatusText(status int) string

StatusText mirrors net/http.StatusText for the codes this package can produce and the ordinary ones beside them, and returns "" for anything else exactly as the standard library does. It exists so the error model links no transport: every constructor below sets Title, so this is reached only by a hand-built HTTPError.

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.

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 FileFromHeader

func FileFromHeader(fh *multipart.FileHeader, limit int64) (File, error)

FileFromHeader reads one multipart part into a File, bounded by limit. Both transports reach this: fasthttp's MultipartForm also yields *multipart.FileHeader, so the part-reading rule is written once.

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 over any writer.

func NewStream

func NewStream[T any](w io.Writer, format StreamFormat) *Stream[T]

NewStream builds a stream over w. The caller has already sent the headers StreamHeaders lists and the 200 status.

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.

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.

Generated encoders terminate each event with a single '\n', which supplies the NDJSON line ending and the first newline of the SSE frame.

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 NegotiateStream

func NegotiateStream(streamQuery, accept, userAgent string) StreamFormat

NegotiateStream selects SSE, NDJSON, or JSON array using:

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

It takes the three values as strings so each transport reads them its own way and the decision itself stays in one place.

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.

type StreamHeader

type StreamHeader struct{ Name, Value string }

StreamHeader is one response header a format requires.

func StreamHeaders

func StreamHeaders(format StreamFormat) []StreamHeader

StreamHeaders lists the headers a format's response opens with, in order, so both surfaces send the same set.

Jump to

Keyboard shortcuts

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