Packages
scrivener_headers_json
1.0.0
Helpers for paginating API responses with Scrivener and HTTP headers, changes link from string to json
Current section
Files
Jump to
Current section
Files
lib/scrivener/headers.ex
defmodule Scrivener.Headers do
@moduledoc """
Helpers for paginating API responses with [Scrivener](https://github.com/drewolson/scrivener) and HTTP headers. Implements [RFC-5988](https://mnot.github.io/I-D/rfc5988bis/), the proposed standard for Web linking.
Use `paginate/2` to set the pagination headers:
def index(conn, params) do
page = MyApp.Person
|> where([p], p.age > 30)
|> order_by([p], desc: p.age)
|> preload(:friends)
|> MyApp.Repo.paginate(params)
conn
|> Scrivener.Headers.paginate(page)
|> render("index.json", people: page.entries)
end
"""
import Plug.Conn, only: [put_resp_header: 3]
@doc """
Add HTTP headers for a `Scrivener.Page`.
"""
@spec paginate(Plug.Conn.t, Scrivener.Page.t) :: Plug.Conn.t
def paginate(conn, page) do
uri = %URI{scheme: Atom.to_string(conn.scheme),
host: conn.host,
port: conn.port,
path: conn.request_path,
query: conn.query_string}
conn
|> put_resp_header(Application.get_env(:scrivener_headers_json, :link), build_link_header(uri, page))
|> put_resp_header(Application.get_env(:scrivener_headers_json, :total), Integer.to_string(page.total_entries))
|> put_resp_header(Application.get_env(:scrivener_headers_json, :per_page), Integer.to_string(page.page_size))
|> put_resp_header(Application.get_env(:scrivener_headers_json, :total_pages), Integer.to_string(page.total_pages))
|> put_resp_header(Application.get_env(:scrivener_headers_json, :page_number), Integer.to_string(page.page_number))
end
@spec build_link_header(URI.t, Scrivener.Page.t) :: String.t
defp build_link_header(uri, page) do
map = %{}
map
|> Map.put("first", link_str(uri, 1))
|> Map.put("last", link_str(uri, page.total_pages))
|> maybe_add_prev(uri, page.page_number, page.total_pages)
|> maybe_add_next(uri, page.page_number, page.total_pages)
|> Poison.encode!
end
defp link_str(%{query: req_query} = uri, page_number) do
query =
req_query
|> URI.decode_query()
|> Map.put("page", page_number)
|> URI.encode_query()
uri_str =
%URI{uri | query: query}
|> URI.to_string()
uri_str
end
defp maybe_add_prev(links, uri, page_number, total_pages) when 1 < page_number and page_number <= total_pages do
Map.put(links, "prev", link_str(uri, page_number - 1))
end
defp maybe_add_prev(links, _uri, _page_number, _total_pages) do
links
end
defp maybe_add_next(links, uri, page_number, total_pages) when 1 <= page_number and page_number < total_pages do
Map.put(links, "next", link_str(uri, page_number + 1))
end
defp maybe_add_next(links, _uri, _page_number, _total_pages) do
links
end
end