Documentation
¶
Overview ¶
Package format bridges Codec[T] to concrete serialization formats (JSON, YAML, TOML, Gob).
A codec works with an intermediate representation (map[string]any) that is format-agnostic. Format wraps that intermediate layer so the same codec can read and write multiple wire formats without any changes to the codec itself.
Text-based formats (JSON, YAML, TOML) pass through the map[string]any intermediate. Binary and typed formats (Gob) bypass the intermediate and operate on the typed value directly via the marshalTyped/unmarshalTyped path.
Index ¶
- Variables
- func FromEnv[T any](c codex.Codec[T], prefix string) (T, error)
- type Format
- func Gob[T any](c codex.Codec[T]) Format[T]
- func JSON[T any](c codex.Codec[T]) Format[T]
- func New[T any](c codex.Codec[T], marshal func(any) ([]byte, error), ...) Format[T]
- func NewStreamed[T any](c codex.Codec[T], marshalTo func(T, io.Writer) error, ...) Format[T]
- func NewTyped[T any](c codex.Codec[T], marshal func(T) ([]byte, error), ...) Format[T]
- func TOML[T any](c codex.Codec[T]) Format[T]
- func YAML[T any](c codex.Codec[T]) Format[T]
- func (f Format[T]) ContentType() string
- func (f Format[T]) IsStreamable() bool
- func (f Format[T]) Marshal(v T) ([]byte, error)
- func (f Format[T]) MarshalTo(v T, w io.Writer) error
- func (f Format[T]) Schema() schema.Schema
- func (f Format[T]) Unmarshal(data []byte) (T, error)
- func (f Format[T]) Validate(v T) error
- func (f Format[T]) WithContentType(ct string) Format[T]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotStreamable = errors.New("format: not streamable — use NewStreamed to create a streaming format")
ErrNotStreamable is returned by Format.MarshalTo when the format was not created with NewStreamed and therefore does not support streaming output.
Functions ¶
func FromEnv ¶ added in v0.3.0
FromEnv loads T from environment variables using schema-driven type coercion.
Naming convention: strings.ToUpper(prefix + field_name). Underscores in field names are preserved:
field "log_level" + prefix "APP_" → "APP_LOG_LEVEL" field "db" + prefix "APP_" → recurse with prefix "APP_DB_" nested field "host" → "APP_DB_HOST"
Supported types (determined from the codec's schema):
flat primitives — direct env var, string coerced by schema type
nested structs — prefix expansion (APP_DB_HOST) OR JSON object (APP_DB='{"host":"..."}')
slices — comma-separated (APP_TAGS=a,b,c) OR JSON array (APP_TAGS='["a","b","c"]')
StringMap — JSON object only (APP_LABELS='{"k":"v"}')
Nullable[T] — absent = nil; present = coerce as inner type
JSON detection: when a field's env var is set and the value starts with '{' or '[' matching the field's schema type, it is parsed as JSON. JSON takes precedence over prefix expansion and comma-split when both would apply (e.g. APP_DB='{...}' takes priority over APP_DB_HOST=...).
Silently skipped: TaggedUnion, slices of objects.
Errors are returned as codex.ValidationErrors. Parse errors (an env var is set but its value cannot be coerced to the field's type) are collected and returned before the codec's Decode runs. Missing required fields and constraint violations are reported by Decode in the same error shape.
Types ¶
type Format ¶
type Format[T any] struct { // contains filtered or unexported fields }
Format binds a Codec[T] to a specific serialization format. Use JSON, YAML, TOML, or Gob to construct one. For formats that operate on the typed value directly (e.g. HTML rendering), use NewTyped. For streaming output (write to io.Writer without buffering), use NewStreamed.
func Gob ¶ added in v0.9.0
Gob returns a Format[T] that serialises T using encoding/gob.
Unlike JSON, YAML, and TOML — which pass a map[string]any intermediate through the codec — Gob encodes and decodes the typed value directly. Codec constraints are enforced on both marshal (before encoding) and unmarshal (after decoding).
Suitable for internal Go-to-Go communication: forge pipelines, MQTT between Go services, and binary caching. Not suitable for REST content negotiation, human-readable output, or cross-language interoperability.
Requirements and limitations:
- All struct fields that gob encodes must be exported; unexported fields are silently skipped.
- For interface values, register concrete types with encoding/gob.Register before use.
- "application/gob" is a conventional content type; it is not an IANA-registered MIME type.
- Observability is handled by the adapter layer — no special configuration needed.
ContentType is "application/gob".
func JSON ¶
JSON returns a Format that reads and writes JSON. ContentType is "application/json".
Example ¶
package main
import (
"fmt"
"github.com/DaniDeer/go-codex/codex"
"github.com/DaniDeer/go-codex/format"
)
func main() {
type Item struct {
Name string
Price float64
}
itemCodec := codex.Struct[Item](
codex.RequiredField("name", codex.String(),
func(i Item) string { return i.Name },
func(i *Item, v string) { i.Name = v },
),
codex.RequiredField("price", codex.Float64(),
func(i Item) float64 { return i.Price },
func(i *Item, v float64) { i.Price = v },
),
)
j := format.JSON(itemCodec)
// Marshal a Go value to JSON bytes.
data, _ := j.Marshal(Item{Name: "Widget", Price: 9.99})
fmt.Println(string(data))
// Unmarshal JSON bytes back to the typed value.
item, _ := j.Unmarshal(data)
fmt.Printf("%s: %.2f\n", item.Name, item.Price)
}
Output: {"name":"Widget","price":9.99} Widget: 9.99
func New ¶
func New[T any](c codex.Codec[T], marshal func(any) ([]byte, error), unmarshal func([]byte) (any, error)) Format[T]
New creates a Format from a codec and custom marshal/unmarshal functions. Use this to integrate formats not covered by the built-in constructors. ContentType is empty by default; call Format.WithContentType to set it.
func NewStreamed ¶ added in v0.8.0
func NewStreamed[T any](c codex.Codec[T], marshalTo func(T, io.Writer) error, unmarshal func([]byte) (T, error), contentType string) Format[T]
NewStreamed creates a Format where responses are written directly to an io.Writer without buffering to a []byte intermediate. This enables chunked or streaming responses for large payloads (HTML pages, JSON arrays, CSV exports).
The codec is used for validation: Format.MarshalTo runs all Refine constraints on the value before calling marshalTo, so invalid data is rejected before any bytes are written.
unmarshal is used for Format.Unmarshal (reading streaming formats is rarely needed; pass a function that returns an error when not applicable).
Use Format.IsStreamable to detect streaming formats. The adapter calls Format.MarshalTo instead of Format.Marshal and writes response headers before streaming, so partial output is never flushed on validation failure.
Example — streaming a templ component without buffering:
streamFmt := format.NewStreamed(
propsCodec,
func(props Props, w io.Writer) error {
return component(props).Render(context.Background(), w)
},
func([]byte) (Props, error) {
var zero Props
return zero, errors.New("HTML is not decodable")
},
"text/html; charset=utf-8",
)
func NewTyped ¶ added in v0.8.0
func NewTyped[T any](c codex.Codec[T], marshal func(T) ([]byte, error), unmarshal func([]byte) (T, error), contentType string) Format[T]
NewTyped creates a Format where the marshal and unmarshal functions operate on the typed value directly, rather than on the intermediate representation. The codec is still used for validation: Format.Marshal runs all Refine constraints on the value before calling marshal, and Format.Validate works as normal.
Use this when the wire format cannot be represented via a map[string]any intermediate — for example, rendering HTML via a templ component:
htmlFormat := format.NewTyped(
propsCodec,
func(props Props) ([]byte, error) {
var buf bytes.Buffer
err := component(props).Render(context.Background(), &buf)
return buf.Bytes(), err
},
func([]byte) (Props, error) {
var zero Props
return zero, errors.New("HTML is not decodable")
},
"text/html; charset=utf-8",
)
func (Format[T]) ContentType ¶ added in v0.8.0
ContentType returns the MIME type associated with this format (e.g. "application/json"). Empty string means the format has no registered content type.
func (Format[T]) IsStreamable ¶ added in v0.8.0
IsStreamable reports whether this format supports streaming output via Format.MarshalTo. Streaming formats are created with NewStreamed.
func (Format[T]) Marshal ¶
Marshal encodes v to bytes using the codec and then the format serializer. If the format was created with NewTyped, the codec validates v first and then the typed marshal function is called directly (bypassing the intermediate). For streaming formats created with NewStreamed, use Format.MarshalTo instead.
func (Format[T]) MarshalTo ¶ added in v0.8.0
MarshalTo validates v via the codec and then writes the serialized form directly to w without buffering to a []byte intermediate. Use this with formats created via NewStreamed; call Format.IsStreamable first. Returns ErrNotStreamable if the format has no streaming marshal function. Validation errors are returned before any bytes are written to w.
func (Format[T]) Unmarshal ¶
Unmarshal deserializes data into an intermediate and then decodes it via the codec. If the format was created with NewTyped, the typed unmarshal function is used directly.
func (Format[T]) Validate ¶
Validate checks v against the codec's constraints without serializing to bytes. It delegates to Codec.Validate — see its documentation for the rationale.
func (Format[T]) WithContentType ¶ added in v0.8.0
WithContentType returns a copy of the format with the given MIME content type set. Use this when registering custom formats for content negotiation.