Cookbook: Autopaginate using "Link" header (sentry version) - elixir-tesla/tesla GitHub Wiki

Cookbook: Autopaginate using "Link" header shows an outdated version that doesn't use the up to date Tesla API.

This showcases a recursive middleware that handles pagination through Sentry's specific implementation of the Link header which contains indication whether the next page contains results in a results=true/false attribute.

It makes new requests from within the middleware to browse all available pages.

https://docs.sentry.io/api/pagination/

defmodule SentryPaginate do
  @behaviour Tesla.Middleware

  @impl Tesla.Middleware
  def call(env, next, _opts) do
    env
    |> Tesla.run(next)
    |> parse_rels()
    |> maybe_get_next(env, next)
  end

  defp maybe_get_next({:ok, %Tesla.Env{status: 200, opts: opts} = res} = env, original_env, next) do
    cond do
      opts[:rels]["next"] ->
        # Copy opts and query params from the response env,
        # these are not modified in the adapters, but middlewares
        # that come after might store state there
        new_env = %{original_env | opts: res.opts, url: opts[:rels]["next"]}

        case call(new_env, next, []) do
          {:ok, %Tesla.Env{status: 200} = new_res} ->
            {:ok, %{new_res | body: res.body ++ new_res.body}}
          error ->
            error
        end

      true ->
        env
    end
  end

  defp parse_rels({:ok, env}), do: {:ok, parse_rels(env)}
  defp parse_rels({:error, reason}), do: {:error, reason}

  defp parse_rels(env) do
    if link = Tesla.get_header(env, "link") do
      Tesla.put_opt(env, :rels, rels(link))
    else
      env
    end
  end

  defp rels(link) do
    link
    |> String.split(",")
    |> Enum.map(&String.trim/1)
    |> Enum.map(&rel/1)
    |> Enum.reject(&is_nil/1)
    |> Enum.into(%{})
  end

  defp rel(item) do
    case Regex.run(~r/\A<(.+)>; rel=["]?([^"]+)["]?; results=["]?([^"]+)["]?/, item, capture: :all_but_first) |> Enum.reverse() do
      ["false", _, _] ->
        nil

      [_ | rest] ->
        List.to_tuple(rest)
    end
  end
end
⚠️ **GitHub.com Fallback** ⚠️