livery_resp (livery v0.1.0)
View SourceResponse constructors and accessors.
Handlers return an immutable #livery_resp{} value. The core
emits it onto the wire by walking the body variant and driving
the adapter's send_headers/send_data/send_trailers calls.
Response builders here are pure: they never touch sockets.
Summary
Functions
Append a header even when one with this name exists.
Remove every header with this name.
Headers-only response.
Send a file from the filesystem.
file/2 with an explicit byte range.
text/html; charset=utf-8 response.
html/2 with extra headers.
Wrap pre-encoded JSON bytes as a response.
json/2 with extra headers.
Newline-delimited JSON streaming response.
ndjson/2 with extra headers.
Build a response with the given status and headers, no body.
Build a response with status, headers, and a body variant.
Redirect response, setting the Location header.
redirect/2 with extra headers.
Server-Sent Events response.
sse/2 with extra headers.
Streaming chunked response.
text/plain; charset=utf-8 response.
text/2 with extra headers.
Protocol upgrade response (WebSocket / WebTransport).
Replace the body variant, keeping status, headers, and trailers.
Set the Cache-Control header.
Set the ETag header.
Replace (or insert) a header. Names are matched case-insensitively.
Attach trailers.
Types
-type body() :: {full, iodata()} | {chunked, fun((term()) -> ok | {error, term()})} | {sse, fun((term()) -> ok | {error, term()})} | {file, file:name_all(), undefined | {non_neg_integer(), non_neg_integer() | eof}} | {upgrade, ws | wt, term()} | empty | taken_over.
-type cache_directive() :: no_cache | no_store | public | private | immutable | must_revalidate | proxy_revalidate | no_transform | {max_age, non_neg_integer()} | {s_maxage, non_neg_integer()} | {stale_while_revalidate, non_neg_integer()} | {stale_if_error, non_neg_integer()}.
-type header_name() :: binary().
-type header_value() :: binary().
-type resp() :: #livery_resp{status :: 100..599, headers :: [{binary(), binary()}], body :: {full, iodata()} | {chunked, fun((term()) -> ok | {error, term()})} | {sse, fun((term()) -> ok | {error, term()})} | {file, file:name_all(), undefined | {non_neg_integer(), non_neg_integer() | eof}} | {upgrade, ws | wt, term()} | empty | taken_over, trailers :: undefined | [{binary(), binary()}] | fun(() -> [{binary(), binary()}])}.
Functions
-spec append_header(header_name(), header_value(), resp()) -> resp().
Append a header even when one with this name exists.
-spec delete_header(header_name(), resp()) -> resp().
Remove every header with this name.
-spec empty(100..599) -> resp().
Headers-only response.
-spec file(100..599, file:name_all()) -> resp().
Send a file from the filesystem.
Range is undefined for the whole file, or {Offset, Length}
where Length may be eof.
-spec file(100..599, file:name_all(), undefined | {non_neg_integer(), non_neg_integer() | eof}) -> resp().
file/2 with an explicit byte range.
-spec headers(resp()) -> [{header_name(), header_value()}].
text/html; charset=utf-8 response.
-spec html(100..599, [{header_name(), header_value()}], iodata()) -> resp().
html/2 with extra headers.
Wrap pre-encoded JSON bytes as a response.
Livery does not bundle a JSON codec. Pass already-encoded iodata.
Higher-level helpers plugging in thoas or jsx can sit on top
of this builder.
-spec json(100..599, [{header_name(), header_value()}], iodata()) -> resp().
json/2 with extra headers.
Newline-delimited JSON streaming response.
The producer is called with an Emit callback that takes any
JSON-encodable Erlang term. Each Emit(Term) encodes the term
via the OTP json module, appends a literal \\n, and writes
one frame. Content-Type defaults to application/x-ndjson.
livery_resp:ndjson(200, fun(Emit) ->
[Emit(#{n => N}) || N <- lists:seq(1, 5)],
ok
end).For pre-encoded bytes, use stream/3 directly.
-spec ndjson(100..599, [{header_name(), header_value()}], fun((term()) -> ok | {error, term()})) -> resp().
ndjson/2 with extra headers.
-spec new(100..599, [{header_name(), header_value()}]) -> resp().
Build a response with the given status and headers, no body.
-spec new(100..599, [{header_name(), header_value()}], body()) -> resp().
Build a response with status, headers, and a body variant.
Redirect response, setting the Location header.
-spec redirect(301 | 302 | 303 | 307 | 308, iodata(), [{header_name(), header_value()}]) -> resp().
redirect/2 with extra headers.
Server-Sent Events response.
-spec sse(100..599, [{header_name(), header_value()}], fun((term()) -> ok | {error, term()})) -> resp().
sse/2 with extra headers.
-spec status(resp()) -> 100..599.
-spec stream(100..599, [{header_name(), header_value()}], fun((term()) -> ok | {error, term()})) -> resp().
Streaming chunked response.
The producer is called with a SendFun and drives body chunks
until it returns.
text/plain; charset=utf-8 response.
-spec text(100..599, [{header_name(), header_value()}], iodata()) -> resp().
text/2 with extra headers.
-spec trailers(resp()) -> undefined | [{header_name(), header_value()}] | fun(() -> [{header_name(), header_value()}]).
Protocol upgrade response (WebSocket / WebTransport).
Replace the body variant, keeping status, headers, and trailers.
Used by middleware (e.g. livery_compress) that rewrites the body
after the handler has produced the response.
-spec with_cache_control(binary() | [cache_directive()], resp()) -> resp().
Set the Cache-Control header.
Pass a verbatim binary, or a list of directives: the atoms no_cache,
no_store, public, private, immutable, must_revalidate,
proxy_revalidate, no_transform, or the tuples {max_age, Secs},
{s_maxage, Secs}, {stale_while_revalidate, Secs},
{stale_if_error, Secs}.
Set the ETag header.
A value already shaped as a strong ("...") or weak (W/"...") tag is
used as-is; a bare token is wrapped as a strong ETag.
-spec with_header(header_name(), header_value(), resp()) -> resp().
Replace (or insert) a header. Names are matched case-insensitively.
-spec with_trailers(undefined | [{header_name(), header_value()}] | fun(() -> [{header_name(), header_value()}]), resp()) -> resp().
Attach trailers.
Pass a list of {Name, Value} pairs computed up front, or a fun
fun() -> [{Name, Value}] evaluated lazily after the body has
been emitted.