Bier.MediaType (bier v0.1.0)

Copy Markdown View Source

Accept/Content-Type media-type negotiation, mirroring PostgREST's PostgREST.MediaType.

A parsed media type is a %Bier.MediaType{} struct carrying the canonical symbol (:json, :csv, :singular, :array_strip, …), the rendered MIME string (toMime), and any preserved parameters (plan for/options, the nulls=stripped flag, etc.).

Negotiation (negotiate/2) takes the request's ordered Accept preferences and the set of media types a producer can emit, and returns the first acceptable one (client order wins), or :not_acceptable.

Summary

Functions

Render the response Content-Type value for a resolved media type. charset controls whether ; charset=utf-8 is appended — every type except octet-stream / custom (:other) / :any carries the charset.

Parse one media type token (no q-value handling) into a struct, or nil for an unrecognized custom/unknown token (still tracked so */* can rescue it).

The query-executor output format for a negotiated media type: :geojson for application/geo+json (rows aggregated into a FeatureCollection via ST_AsGeoJSON), :json_strip for any nulls=stripped type (the aggregate is wrapped in json_strip_nulls, upstream's addNullsToSnip), :csv for text/csv (rows aggregated as ordered [key, value] pair lists), :json for everything else.

The media type a producer emits for symbol — the same struct negotiate/2 yields for that type.

Negotiate the client's ordered Accept preferences against the producer's available media types (a list of symbols). Returns {:ok, %MediaType{}} for the first acceptable preference (client order wins), or :not_acceptable.

Parse an Accept header into an ordered list of %Bier.MediaType{} entries. Order follows client order (PostgREST does not reorder by q-value); a q=0 entry is dropped.

Types

t()

@type t() :: %Bier.MediaType{mime: String.t(), params: map(), symbol: atom()}

Functions

content_type(mt)

Render the response Content-Type value for a resolved media type. charset controls whether ; charset=utf-8 is appended — every type except octet-stream / custom (:other) / :any carries the charset.

decode(token)

Parse one media type token (no q-value handling) into a struct, or nil for an unrecognized custom/unknown token (still tracked so */* can rescue it).

executor_format(arg1)

The query-executor output format for a negotiated media type: :geojson for application/geo+json (rows aggregated into a FeatureCollection via ST_AsGeoJSON), :json_strip for any nulls=stripped type (the aggregate is wrapped in json_strip_nulls, upstream's addNullsToSnip), :csv for text/csv (rows aggregated as ordered [key, value] pair lists), :json for everything else.

These belong in SQL rather than in Bier.Render because decoding the body into Elixir terms and re-encoding it loses JSON key order and the exact numeric text PostgreSQL emitted (#109, #110).

for_symbol(symbol)

@spec for_symbol(atom()) :: t()

The media type a producer emits for symbol — the same struct negotiate/2 yields for that type.

Used where the response's Content-Type is fixed by the resource instead of being negotiated: the generated root document always renders toContentType MTOpenAPI whatever the request asked for (Response.hs actionResponse (MaybeDbResult InspectPlan …)).

negotiate(accepts, available)

Negotiate the client's ordered Accept preferences against the producer's available media types (a list of symbols). Returns {:ok, %MediaType{}} for the first acceptable preference (client order wins), or :not_acceptable.

*/* matches the producer's default (first available). A specific preference listed before */* overrides */*.

parse_accept(header)

Parse an Accept header into an ordered list of %Bier.MediaType{} entries. Order follows client order (PostgREST does not reorder by q-value); a q=0 entry is dropped.