Skip to content

Instantly share code, notes, and snippets.

@sb8244
Created December 22, 2021 07:35
Show Gist options
  • Save sb8244/fb762ff9e12a5977f0539531cbccf7cc to your computer and use it in GitHub Desktop.
Save sb8244/fb762ff9e12a5977f0539531cbccf7cc to your computer and use it in GitHub Desktop.
Example of fetching pages and blocks from Notion's public API in Elixir
defmodule Clove.Connections.Client.Notion do
# There is not a way to filter last_edited_time, so consumer should check if it needs to fetch the blocks or not
# This will help for deletion detection, though
def retrieve_pages(connection) do
request = %{
method: :post,
url: "#{base_url()}/v1/search",
params: %{
"query" => "",
"sort" => %{
"direction" => "descending",
"timestamp" => "last_edited_time"
},
"filter" => %{
"property" => "object",
"value" => "page"
},
"page_size" => 100
}
}
retrieve_paged([], request, :start, connection)
end
def retrieve_child_blocks(parent_id, connection, opts = [recursive?: recurse?]) do
request = %{
method: :get,
url: "#{base_url()}/v1/blocks/#{parent_id}/children",
params: %{
"page_size" => 100
}
}
blocks = retrieve_paged([], request, :start, connection)
Enum.map(blocks, fn
block = %{"has_children" => true} ->
if recurse? do
child_blocks = retrieve_child_blocks(block["id"], connection, opts)
Map.put(block, "_children", child_blocks)
else
block
end
block ->
block
end)
end
defp retrieve_paged(results, _request, nil, _connection), do: results
defp retrieve_paged(results, request, cursor, connection) do
resp = do_request(request, cursor, connection)
next_results = results ++ Map.get(resp, "results", [])
next_cursor = Map.get(resp, "next_cursor")
retrieve_paged(next_results, request, next_cursor, connection)
end
defp do_request(%{method: :get, url: url, params: base_params}, cursor, connection) do
params = maybe_add_cursor(base_params, cursor)
query = Plug.Conn.Query.encode(params)
url = URI.parse(url) |> Map.put(:query, query) |> URI.to_string()
case HTTPoison.get(url, headers(connection), hackney_opts()) do
{:ok, %{body: body, status_code: 200}} -> Jason.decode!(body)
{_status, resp} -> raise Clove.Connections.ApiError, resp
end
end
defp do_request(%{method: :post, url: url, params: base_params}, cursor, connection) do
params = maybe_add_cursor(base_params, cursor)
case HTTPoison.post(url, Jason.encode!(params), headers(connection), hackney_opts()) do
{:ok, %{body: body, status_code: 200}} -> Jason.decode!(body)
{_status, resp} -> raise Clove.Connections.ApiError, resp
end
end
defp maybe_add_cursor(params, cursor) do
case cursor do
:start -> params
nil -> params
cur -> Map.put(params, "start_cursor", cur)
end
end
defp headers(%{access_token: token}) do
[
{"Content-Type", "application/json"},
{"Authorization", "Bearer #{token}"},
{"Notion-Version", "2021-05-13"}
]
end
defp hackney_opts(opts \\ []) do
[
pool: :external,
recv_timeout: Keyword.get(opts, :recv_timeout, 45_000)
]
end
defp base_url do
Process.get(:notion_bypass_url) || "https://api.notion.com"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment