astarteapi

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package astarteapi implements the JSON envelope conventions shared by every Astarte-compatible REST surface: success bodies are wrapped as {"data": ...}, error bodies as {"errors": {"detail": "..."}} (or the field-keyed changeset shape used by 422 validation failures), and request bodies arrive wrapped as {"data": ...}.

These exact bytes are parsed by astartectl and the official device SDKs, so the golden fixtures under testdata/ are wire-frozen: changing any envelope produced here is a compatibility break, not a refactor.

Index

Constants

View Source
const (
	// DetailBadRequest is the canonical 400 detail. Measured upstream 1.2.0
	// (2026-08-24, verify batch #57): Phoenix renders "Bad request" — the
	// capital-R form this constant carried before was reconstructed, not
	// observed, and every probed 400 row answers with the lowercase r.
	DetailBadRequest = "Bad request"
	// DetailUnauthorized is the canonical 401 detail.
	DetailUnauthorized = "Unauthorized"
	// DetailForbidden is the canonical 403 detail.
	DetailForbidden = "Forbidden"
	// DetailNotFound is the canonical generic 404 detail.
	DetailNotFound = "Not Found"
	// DetailDeviceNotFound is the canonical 404 detail for unknown devices
	// (upstream AppEngine/Pairing shape).
	DetailDeviceNotFound = "Device not found"
	// DetailRouteNotFound is the 404 detail upstream AppEngine and
	// RealmManagement emit for a path matching no route at all. Distinct from
	// DetailNotFound, which a handler emits for a route that matched and found
	// no resource; the capitalisation difference is upstream's, not a typo.
	DetailRouteNotFound = "Not found"
	// DetailPageNotFound is the 404 detail upstream Pairing emits for a path
	// matching no route at all.
	DetailPageNotFound = "Page not found"
	// DetailInternalServerError is the canonical 500 detail. Measured
	// upstream 1.2.0 (2026-08-24, verify batch #57): Phoenix renders
	// "Internal server error" — the capital-S form was reconstructed.
	DetailInternalServerError = "Internal server error"
)

Canonical upstream error detail strings. These are frozen: SDK and astartectl error paths match on them.

View Source
const ContentType = "application/json; charset=utf-8"

ContentType is the Content-Type header value set on every envelope, matching what upstream Astarte's Phoenix endpoints emit.

View Source
const DefaultMaxBodyBytes int64 = 1 << 20 // 1 MiB

DefaultMaxBodyBytes is the request body size cap callers are expected to pass to DecodeData unless an endpoint has a documented reason to differ (interface uploads, for example, may need more than a pairing request).

Variables

View Source
var ErrBodyTooLarge = errors.New("request body too large")

ErrBodyTooLarge is wrapped by DecodeData when the request body exceeds the caller-supplied size cap.

View Source
var ErrMissingData = errors.New(`missing "data" key in request body`)

ErrMissingData is wrapped by DecodeData when the request body has no "data" key (or it is JSON null) — upstream rejects such bodies uniformly.

Functions

func DecodeData

func DecodeData(r io.Reader, maxBytes int64, dst any) error

DecodeData reads at most maxBytes bytes from r, unwraps the mandatory {"data": ...} request envelope, and unmarshals the "data" value into dst.

It fails with an error wrapping ErrBodyTooLarge when the body exceeds maxBytes, with one wrapping ErrMissingData when the "data" key is absent or null, and with the underlying JSON error for malformed bodies (including trailing garbage after the top-level value). Sibling keys next to "data" are ignored, matching upstream parameter handling.

func WriteBadRequest

func WriteBadRequest(w http.ResponseWriter) error

WriteBadRequest writes the canonical 400 envelope.

func WriteData

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

WriteData writes {"data": v} with the given status code.

func WriteDataWithLinks(w http.ResponseWriter, status int, v any, links Links) error

WriteDataWithLinks writes {"data": v, "links": links} with the given status code (upstream paged-collection shape).

func WriteDataWithMetadata added in v0.2.0

func WriteDataWithMetadata(w http.ResponseWriter, status int, v any, m map[string]any) error

WriteDataWithMetadata writes {"data": v, "metadata": m}; m == nil omits the key (upstream format=table responses carry column metadata this way).

func WriteDeviceNotFound

func WriteDeviceNotFound(w http.ResponseWriter) error

WriteDeviceNotFound writes the canonical 404 "Device not found" envelope.

func WriteError

func WriteError(w http.ResponseWriter, status int, detail string) error

WriteError writes {"errors": {"detail": detail}} with the given status code. Use the canonical constructors below for the frozen upstream shapes; use WriteError directly for endpoint-specific details.

func WriteFieldErrors

func WriteFieldErrors(w http.ResponseWriter, status int, fields map[string][]string) error

WriteFieldErrors writes the Phoenix-changeset-shaped error envelope {"errors": {"<field>": ["<message>", ...]}} used by upstream 422 validation failures (for example {"errors": {"hw_id": ["is invalid"]}}). Keys are emitted in sorted order (Go map marshalling), which matches the deterministic bodies upstream produces for single-field failures.

func WriteForbidden

func WriteForbidden(w http.ResponseWriter) error

WriteForbidden writes the canonical 403 envelope.

func WriteInternalServerError

func WriteInternalServerError(w http.ResponseWriter) error

WriteInternalServerError writes the canonical 500 envelope.

func WriteNotFound

func WriteNotFound(w http.ResponseWriter) error

WriteNotFound writes the canonical generic 404 envelope.

func WriteRawErrors added in v0.2.0

func WriteRawErrors(w http.ResponseWriter, status int, errs any) error

WriteRawErrors writes {"errors": <anything>} — caller-shaped error bodies for the nested changeset envelopes upstream uses inside sub-objects (for example a trigger's {"action": {"http_url": [...]}}). Map keys are emitted in sorted order, without HTML escaping, and without a trailing newline, like every envelope here.

func WriteUnauthorized

func WriteUnauthorized(w http.ResponseWriter) error

WriteUnauthorized writes the canonical 401 envelope.

Types

type Links struct {
	Self string `json:"self"`
	Next string `json:"next,omitempty"`
}

Links is the upstream pagination links object carried alongside data on paged collections (the dashboard extracts the next-page cursor from links.next).

Jump to

Keyboard shortcuts

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