Zizq.Codec behaviour (Zizq v0.6.0-alpha.9)

Copy Markdown View Source

Serialization format used for request and response bodies.

The Zizq server speaks both JSON and MessagePack on every endpoint, and the two are freely interchangeable: a job enqueued as MessagePack can be read back as JSON, so a producer and a consumer need not be configured with the same codec — or even be written in the same language. Choose Zizq.Codec.MessagePack (the default) for compactness, or Zizq.Codec.JSON when you want human-readable traffic.

Payloads

Whichever codec is in use, a job payload must be JSON-compatible. The server types payloads as a JSON value, so MessagePack's binary (bin) type is rejected. Encode raw bytes as base64 in a string, exactly as you would with JSON. Both codecs also hand payloads back with string keys, since neither preserves atoms, so perform/2 pattern matches identically either way.

Custom codecs

The behaviour is public so a project stuck on an Elixir older than 1.18 (before the built-in JSON module) can theoretically supply a Jason-backed codec without this library carrying the dependency.

Summary

Types

Shorthand names for the built-in codecs.

t()

A module implementing this behaviour.

Callbacks

Media type for request/response bodies.

Deserialize a response body. Accepts iodata.

Serialize a term into a request body.

How streaming endpoints delimit records.

Media type for streaming endpoints.

Functions

Resolve a codec from a shorthand name, or validate a module.

Resolve a codec from a Content-Type header value.

Types

format()

@type format() :: :json | :msgpack

Shorthand names for the built-in codecs.

t()

@type t() :: module()

A module implementing this behaviour.

Callbacks

content_type()

@callback content_type() :: String.t()

Media type for request/response bodies.

decode(iodata)

@callback decode(iodata()) :: {:ok, term()} | {:error, Exception.t()}

Deserialize a response body. Accepts iodata.

encode(term)

@callback encode(term()) :: {:ok, iodata()} | {:error, Exception.t()}

Serialize a term into a request body.

Returns iodata rather than a binary so the HTTP layer can write it without a final concatenation.

framing()

@callback framing() :: :line_delimited | :length_prefixed

How streaming endpoints delimit records.

  • :line_delimited — one record per line, terminated by \n; an empty line is a heartbeat.
  • :length_prefixed — each record is a big-endian u32 byte count followed by that many bytes; a zero length is a heartbeat.

Declared here rather than inferred from the codec module so a custom codec can say which framing its format uses.

stream_content_type()

@callback stream_content_type() :: String.t()

Media type for streaming endpoints.

Streaming is framed differently from a request/response body (newline-delimited JSON, or length-prefixed MessagePack), so it negotiates a distinct media type.

Functions

fetch!(module)

@spec fetch!(format() | t()) :: t()

Resolve a codec from a shorthand name, or validate a module.

Examples

iex> Zizq.Codec.fetch!(:msgpack)
Zizq.Codec.MessagePack

iex> Zizq.Codec.fetch!(Zizq.Codec.JSON)
Zizq.Codec.JSON

from_content_type(value)

@spec from_content_type(String.t()) :: {:ok, t()} | :error

Resolve a codec from a Content-Type header value.

Recognises both the request/response media types and the streaming ones, ignores any parameters (; charset=utf-8), and matches case-insensitively as RFC 9110 requires — a proxy is free to rewrite the casing. Returns :error for anything unrecognised so callers can fall back to the configured codec.

Examples

iex> Zizq.Codec.from_content_type("application/json; charset=utf-8")
{:ok, Zizq.Codec.JSON}

iex> Zizq.Codec.from_content_type("application/vnd.zizq.msgpack-stream")
{:ok, Zizq.Codec.MessagePack}

iex> Zizq.Codec.from_content_type("text/plain")
:error