Typelizer.Envelope (Typelizer v0.2.0)

Copy Markdown View Source

Wraps JSON-ready data in an envelope: %{"data" => ..., "meta" => ...}.

json(conn, Typelizer.Envelope.wrap(MyAppWeb.TaskSerializer.serialize_many(tasks)))

json(conn, Typelizer.Envelope.paginated(
  MyAppWeb.TaskSerializer.serialize_many(page.entries),
  page: page.page_number, page_size: page.page_size, total: page.total_entries
))

The matching types are the specs {:envelope, spec}, {:envelope, spec, meta_spec}, {:paginated, item_spec} and {:cursor_paginated, item_spec}, which generate Envelope<T, M>, Paginated<T> and CursorPaginated<T> in TypeScript.

The data is not changed: serialize it first. The keys of the meta map follow the key transform (:camel by default: page_size → pageSize).

See the Serializers guide.

Summary

Types

t()

An envelope: data, and meta when there is one.

Functions

Wraps one page of a list with cursor pagination metadata.

Wraps one page of a list with page-based pagination metadata.

Wraps data in an envelope. meta is optional; its keys follow the key transform, at every level.

Types

t()

@type t() :: %{required(String.t()) => term()}

An envelope: data, and meta when there is one.

Functions

cursor_paginated(entries, opts \\ [])

@spec cursor_paginated(list(), keyword() | map()) :: t()

Wraps one page of a list with cursor pagination metadata.

Options: :next_cursor and :previous_cursor, strings or nil (the default).

iex> Typelizer.Envelope.cursor_paginated([], next_cursor: "g3Q")
%{"data" => [], "meta" => %{"nextCursor" => "g3Q", "previousCursor" => nil}}

paginated(entries, opts)

@spec paginated(list(), keyword() | map()) :: t()

Wraps one page of a list with page-based pagination metadata.

Options (required): :page (1-based), :page_size and :total (the number of entries in all pages). totalPages is computed.

iex> Typelizer.Envelope.paginated([%{"id" => 1}], page: 2, page_size: 10, total: 11)
%{
  "data" => [%{"id" => 1}],
  "meta" => %{"page" => 2, "pageSize" => 10, "total" => 11, "totalPages" => 2}
}

wrap(data, meta \\ nil, opts \\ [])

@spec wrap(term(), map() | keyword() | nil, keyword()) :: t()

Wraps data in an envelope. meta is optional; its keys follow the key transform, at every level.

Options:

  • :key_transform - :camel or :snake. Default: config :typelizer, :key_transform. Set it to the key transform of the serializer whose {:envelope, spec, meta_spec} field holds the value, so the meta keys match its type.

    iex> Typelizer.Envelope.wrap([1, 2]) %{"data" => [1, 2]}

    iex> Typelizer.Envelope.wrap([1, 2], %{generated_at: "2026-09-30", source_ids: [3]}) %{"data" => [1, 2], "meta" => %{"generatedAt" => "2026-09-30", "sourceIds" => [3]}}

    iex> Typelizer.Envelope.wrap([1, 2], [generated_at: "2026-09-30"], key_transform: :snake) %{"data" => [1, 2], "meta" => %{"generated_at" => "2026-09-30"}}