-
Notifications
You must be signed in to change notification settings - Fork 346
Cookbook: Autopaginate using "Link" header
Tymon Tobolski edited this page Mar 26, 2018
·
1 revision
defmodule AutoPaginate do
# requires tesla 0.x
def call(env, run, []) do
env = run.(env)
if env.status == 200 && Map.has_key?(env, :rels) do
next_page = page(env.rels["next"])
last_page = page(env.rels["last"])
cond do
next_page == 2 && last_page ->
body = fetch_parallel(env, next_page, last_page)
%{env | body: (env.body ++ body)}
!last_page && next_page ->
body = fetch_next(env).body
%{env | body: (env.body ++ body)}
true ->
env
end
else
env
end
end
defp fetch_parallel(env, next_page, last_page) do
(next_page..last_page)
|> Gitalyzer.Utils.parmap(fn e -> fetch_page(env, e) end)
|> Enum.reduce([], fn(e,a) -> a ++ e.body end)
end
defp page(rel) do
if rel do
Regex.run(~r/\A.+page=(\d+)\z/, rel, capture: :all_but_first)
|> List.first
|> String.to_integer
else
nil
end
end
defp with_page(url, page) do
url |> String.replace("2", to_string(page))
end
defp fetch_page(env, page) do
env._client |> env._module.get(with_page(env.rels["next"], page))
end
defp fetch_next(env) do
env._client |> env._module.get(env.rels["next"])
end
end
defmodule MyApi do
use Tesla
plug Tesla.Middleware.DecodeRels
plug Autopaginate
end