WhatsApp.Page (WhatsApp SDK v0.1.0)

Copy Markdown View Source

Paginated API response with cursor-based navigation.

Supports eager fetching (list one page) and lazy streaming (process all pages via Stream).

WhatsApp Pagination Format

The WhatsApp Cloud API uses cursor-based pagination:

%{
  "data" => [...],
  "paging" => %{
    "cursors" => %{"before" => "QVFIUl...", "after" => "QVFIUk..."},
    "next" => "https://graph.facebook.com/v23.0/.../message_templates?after=QVFIUk...",
    "previous" => "https://graph.facebook.com/v23.0/.../message_templates?before=QVFIUl..."
  }
}

Usage

# Parse a response into a Page
page = WhatsApp.Page.from_response(response_body, &deserialize/1)

# Check for more pages
WhatsApp.Page.has_next?(page)

# Stream all items across all pages lazily
page
|> WhatsApp.Page.stream(client)
|> Stream.filter(&active?/1)
|> Enum.to_list()

Summary

Functions

Parse a paginated API response into a Page struct.

Returns true if the page has a next page URL.

Returns true if the page has a previous page URL.

Create a lazy stream that auto-pages through all items.

Types

t()

@type t() :: %WhatsApp.Page{
  cursors: %{before: String.t() | nil, after: String.t() | nil},
  data: list(),
  next_url: String.t() | nil,
  previous_url: String.t() | nil
}

Functions

from_response(response_map, deserialize_fn)

@spec from_response(map(), (map() -> any()) | nil) :: t()

Parse a paginated API response into a Page struct.

response_map is the decoded JSON map with "data" and "paging" keys. deserialize_fn is a function that transforms each data item. Pass nil to keep raw maps.

Examples

iex> response = %{"data" => [%{"id" => "1"}], "paging" => %{"cursors" => %{"after" => "abc"}}}
iex> page = WhatsApp.Page.from_response(response, nil)
iex> page.data
[%{"id" => "1"}]

has_next?(page)

@spec has_next?(t()) :: boolean()

Returns true if the page has a next page URL.

Examples

iex> WhatsApp.Page.has_next?(%WhatsApp.Page{next_url: "https://..."})
true

iex> WhatsApp.Page.has_next?(%WhatsApp.Page{next_url: nil})
false

has_previous?(page)

@spec has_previous?(t()) :: boolean()

Returns true if the page has a previous page URL.

Examples

iex> WhatsApp.Page.has_previous?(%WhatsApp.Page{previous_url: "https://..."})
true

iex> WhatsApp.Page.has_previous?(%WhatsApp.Page{previous_url: nil})
false

stream(page, client, opts \\ [])

@spec stream(t(), WhatsApp.Client.t() | nil, keyword()) :: Enumerable.t()

Create a lazy stream that auto-pages through all items.

Uses Stream.unfold/2 to yield individual items from the current page, then automatically fetches the next page when data is exhausted.

The stream stops when there are no more pages or on fetch error.

Options

  • :deserialize_fn - Function to apply to items from fetched pages. Items from the initial page are yielded as-is (already deserialized by from_response/2).
  • :fetch_fn - Custom fetch function (client, url) -> {:ok, map()} | {:error, term()}. Defaults to WhatsApp.Client.request_url/2. Useful for testing.

Examples

# Stream all templates across all pages
page
|> WhatsApp.Page.stream(client, deserialize_fn: &deserialize/1)
|> Enum.to_list()

# Take only the first 50 items (lazy — fetches only needed pages)
page
|> WhatsApp.Page.stream(client)
|> Enum.take(50)