Documentation
¶
Overview ¶
Package httpapi wires the barqr HTTP surface: routing, middleware, request decoding, and error mapping.
The package owns the server lifecycle as well as the routes, so that cmd/barqr stays a thin wiring layer: parse config, build a Server, Run it until the context is cancelled.
Index ¶
Constants ¶
const ( CodeBadRequest = "BAD_REQUEST" CodeUnknownField = "UNKNOWN_FIELD" CodeInvalidValue = "INVALID_VALUE" CodeMissingData = "MISSING_DATA" CodeUnknownType = "UNKNOWN_TYPE" CodeInvalidPayload = "INVALID_PAYLOAD" CodeUnknownSymbology = "UNKNOWN_SYMBOLOGY" CodeDataTooLong = "DATA_TOO_LONG" CodeInvalidData = "INVALID_DATA" CodeUnsupported = "UNSUPPORTED_OPTION" CodeUnknownFormat = "UNKNOWN_FORMAT" CodeUnknownShape = "UNKNOWN_SHAPE" CodeInvalidColor = "INVALID_COLOR" CodeCanvasTooLarge = "CANVAS_TOO_LARGE" CodeUnscannable = "UNSCANNABLE" CodeBodyTooLarge = "BODY_TOO_LARGE" CodeRateLimited = "RATE_LIMITED" CodeTimeout = "TIMEOUT" CodeOverloaded = "OVERLOADED" CodeNotFound = "NOT_FOUND" CodeMethodNotAllowed = "METHOD_NOT_ALLOWED" CodeInternal = "INTERNAL" )
Error codes. These are the stable contract: a client switches on the code, never on the message, so a code is never renamed once released.
const ( // CodeFetchNotAllowed means the host is not on BARQR_FETCH_ALLOWLIST, or // remote fetching is on but nothing was ever allowlisted. CodeFetchNotAllowed = "FETCH_NOT_ALLOWED" // CodeFetchBlocked means the host resolved to an address barqr will not // connect to. CodeFetchBlocked = "FETCH_BLOCKED" )
Error codes for the remote-fetch guards. Both are refusals of policy rather than of syntax — the request is well formed and barqr will not make it — so neither reuses a code that means "you typed it wrong".
Variables ¶
var Auto = AutoInt{}
Auto is the automatic AutoInt, and the zero value of the type.
Functions ¶
func Codes ¶
func Codes() []string
Codes is every error code this build can return, sorted.
It exists so the catalogue in docs/API.md can be checked against the code rather than against a second hand-maintained list — which would be the same drift the documentation tests exist to prevent, one level up.
A new code must be added here as well as declared above. That is deliberate friction: a code is API surface, and adding one without documenting it should cost something.
func Defaults ¶ added in v0.2.0
Defaults maps every request path that has a real, expressible default onto that default, read from the code that actually applies it.
Nothing here is a retyped literal. A default typed out a second time is a second source of truth, and the two drift apart silently — which is exactly what happened to style.hri: the service defaulted it on, docs/API.md said so correctly, and the generated OpenAPI document said nothing at all, so a caller reading the spec and assuming false got true. Sourcing the value from render.DefaultStyle() and friends means the document cannot make that claim wrongly, and a test asserts the document and this map agree in both directions.
It takes the configuration because two of the defaults are per-instance: a document generated by one deployment describes that deployment, which is the whole point of generating it at request time rather than committing a snapshot (ADR-013).
Types ¶
type AutoInt ¶
type AutoInt struct {
// Set reports whether an explicit value was supplied.
Set bool
// Value is meaningful only when Set is true.
Value int
}
AutoInt is an integer option that also accepts the literal "auto".
The QR specification calls these "automatic" rather than "0", and `0` is a legal value for a mask pattern, so a plain int cannot express "not set". The zero value is automatic, which is what a caller who omits the field means.
func (AutoInt) MarshalJSON ¶
MarshalJSON emits the number, or "auto" when unset.
func (*AutoInt) UnmarshalJSON ¶
UnmarshalJSON accepts a number or the string "auto".
type EncodeSection ¶
type EncodeSection struct {
// ECC is the error-correction level. Empty means the configured default.
ECC string `json:"ecc,omitempty"`
// Version pins the symbology version. Zero or "auto" selects it.
Version AutoInt `json:"version,omitzero"`
// Mask pins the data-mask pattern. Zero value or "auto" selects it.
Mask AutoInt `json:"mask,omitzero"`
// QuietZone overrides the margin in modules. Nil uses the symbology's own.
QuietZone *int `json:"quiet_zone,omitempty"`
}
EncodeSection holds the symbology-level options.
type Fault ¶
type Fault struct {
// Code is the stable machine-readable identifier.
Code string `json:"code"`
// Message is a human-readable summary.
Message string `json:"message"`
// Field is the offending request field in dot notation, when there is one.
Field string `json:"field,omitempty"`
// Expected and Got describe the mismatch.
Expected string `json:"expected,omitempty"`
Got string `json:"got,omitempty"`
// Hint is the next thing to try.
Hint string `json:"hint,omitempty"`
// RequestID correlates with the server log line.
RequestID string `json:"request_id,omitempty"`
// contains filtered or unexported fields
}
Fault is the single error shape barqr returns, from every endpoint and every layer. It is deliberately flat and self-describing: a caller should be able to fix their request from the response alone, without reading the docs.
It never carries a stack trace, a file path, an environment value, or an internal type name.
type MetaSection ¶
type MetaSection struct {
// Filename names the file in Content-Disposition.
Filename string `json:"filename,omitempty"`
// Attachment switches Content-Disposition from inline to attachment.
Attachment bool `json:"attachment,omitempty"`
}
MetaSection holds response-shaping options that do not affect the image.
type OutputSection ¶
type OutputSection struct {
// Format names a registered writer. Empty means the configured default.
Format string `json:"format,omitempty"`
// Scale is pixels per module. Zero means derive from Size, else default.
Scale int `json:"scale,omitempty"`
// Size is the target width in Unit. Zero means derive from Scale.
Size float64 `json:"size,omitempty"`
// Unit interprets Size: px, mm, or in.
Unit string `json:"unit,omitempty"`
// DPI converts physical units to pixels. Zero means 300.
DPI int `json:"dpi,omitempty"`
// Quality is the JPEG and WebP quality, 1..100. Zero means 92.
Quality int `json:"quality,omitempty"`
}
OutputSection holds the serialisation options.
type Request ¶
type Request struct {
// Type names a builder. When set, Payload is built into the encoded
// string and Data is ignored.
Type string `json:"type,omitempty"`
// Payload is the builder's input. Query and multipart set its members
// with `payload.<key>=<value>`.
Payload map[string]any `json:"payload,omitempty"`
// Data is the raw string to encode when no Type is given.
Data string `json:"data,omitempty"`
// Symbology names the encoder. Empty means the endpoint's default: "qr"
// for /v1/qr, the path parameter for /v1/barcode/{symbology}.
Symbology string `json:"symbology,omitempty"`
Encode EncodeSection `json:"encode,omitzero"`
Style StyleSection `json:"style,omitzero"`
Output OutputSection `json:"output,omitzero"`
Meta MetaSection `json:"meta,omitzero"`
}
Request is the one request shape barqr accepts, from all three transports.
A query string, a JSON body, and a multipart form all decode into this same struct: the query uses dot notation (`style.module=dot`), JSON uses nesting, and multipart uses the query's flat keys. Keeping a single struct is what makes "every option reachable as a query param or a body field" true by construction rather than by discipline.
Unset is distinguishable from zero throughout. Scalars use a sentinel — an empty string, or zero where zero is not a legal value — and options where zero *is* legal use a pointer or AutoInt.
func Decode ¶
Decode builds a Request from any of the three transports.
The order is deliberate: query parameters first, then the body. A body is the more specific statement of intent, so on a POST with both, the body wins. For multipart, file parts are applied last so an uploaded logo overrides a string field of the same name.
defaultSymbology is what the endpoint implies — "qr" for /v1/qr, the path parameter for /v1/barcode/{symbology}.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the barqr HTTP service.
A Server is created by New, its routes are fixed at construction, and it is driven by Run. Beyond readiness and the rate-limiter's buckets it holds no state, in keeping with the stateless process model.
func (*Server) Handler ¶
Handler exposes the routed handler for testing and for embedding barqr in another server.
func (*Server) Listen ¶
Listen binds the configured address and returns the listener. It is separate from Serve so that a caller — a test, or a socket-activated deployment — can supply its own listener.
type StyleSection ¶
type StyleSection struct {
// Module, Eye, and EyeBall name registered shapes.
Module string `json:"module,omitempty"`
Eye string `json:"eye,omitempty"`
EyeBall string `json:"eye_ball,omitempty"`
// FG, BG, and EyeFG are colours: #rgb, #rrggbb, #rrggbbaa, or a name.
FG string `json:"fg,omitempty"`
BG string `json:"bg,omitempty"`
EyeFG string `json:"eye_fg,omitempty"`
// BarHeight is the height of a linear code in modules. Zero is automatic.
BarHeight int `json:"bar_height,omitempty"`
// HRI controls the human-readable text under a linear code. Nil means on.
HRI *bool `json:"hri,omitempty"`
// HRISize is the height of that text in modules. Zero means the default.
HRISize float64 `json:"hri_size,omitempty"`
// HRIFont is the type family for it: mono or sans. Empty means mono.
HRIFont string `json:"hri_font,omitempty"`
// Logo is a data URI or, when remote fetching is enabled, a URL.
Logo string `json:"logo,omitempty"`
// LogoScale is the logo's width as a fraction of the code, 0.05..0.35.
LogoScale float64 `json:"logo_scale,omitempty"`
// Excavate clears the modules behind the logo instead of drawing over
// them, which reads better but costs error-correction headroom.
Excavate *bool `json:"excavate,omitempty"`
// LogoPadding is the clear space around the logo, in modules.
LogoPadding *int `json:"logo_padding,omitempty"`
// Caption is text drawn beneath the code.
Caption string `json:"caption,omitempty"`
// Frame names a frame style drawn around the code: border, rounded,
// banner, or bubble.
Frame string `json:"frame,omitempty"`
// FrameColor and FrameWidth style that frame. An unset colour follows the
// foreground, and an unset width takes the renderer's default.
FrameColor string `json:"frame_color,omitempty"`
FrameWidth *int `json:"frame_width,omitempty"`
// CaptionColor colours the caption text.
CaptionColor string `json:"caption_color,omitempty"`
// Gradient replaces the flat foreground on data modules, e.g.
// "linear(45deg,#000,#00f)" or "radial(#000,#333)".
Gradient string `json:"gradient,omitempty"`
}
StyleSection holds the appearance options.