Current section
Files
Jump to
Current section
Files
lib/contentful_delivery/entries.ex
defmodule Contentful.Delivery.Entries do
@moduledoc """
Collects functions around the reading of entries from a `Contentful.Space`
"""
alias Contentful.Collection
alias Contentful.CollectionStream
alias Contentful.Delivery
alias Contentful.Entry
alias Contentful.SysData
alias Contentful.Space
@behaviour Collection
@behaviour CollectionStream
@doc """
Will fetch a single entry for a given Contentful.Space within an `environment`.
Actually fetches the entry eagerly and will call the API immediately.
## Examples
space = "my_space_id"
{:ok, %Entry{ sys: %SysData{ id: "my_entry_id"}}}
= space |> Entries.fetch_one("my_entry_id")
# for envs other than "master"
environment = "staging"
{:ok, %Entry{ sys: %SysData{ id: "my_entry_id"}}}
= space |> Entries.fetch_one("my_entry_id", environment)
# override access token
environment = "my_personal_env"
my_access_token = "foobarBAZ"
{:ok, %Entry{ sys: %SysData{ id: "my_entry_id"}}}
= space |> Entries.fetch_one("my_entry_id", environment, my_access_token)
"""
@impl Collection
@spec fetch_one(
String.t(),
Space.t() | String.t(),
String.t() | nil,
String.t() | nil
) ::
{:ok, Entry.t()}
| {:error, atom(), original_message: String.t()}
| {:error, :rate_limit_exceeded, wait_for: integer()}
| {:error, :unknown}
def fetch_one(
entry_id,
space_id \\ Delivery.config(:space_id),
env \\ Delivery.config(:environment),
api_key \\ Delivery.config(:access_token)
)
def fetch_one(entry_id, %Space{sys: %{id: space_id}}, env, api_key) do
space_id
|> build_single_request(entry_id, env, api_key)
|> Delivery.send_request()
|> Delivery.parse_response(&build_entry/1)
end
def fetch_one(entry_id, space_id, env, api_key) do
fetch_one(entry_id, %Space{sys: %{id: space_id}}, env, api_key)
end
@doc """
Can be used fetch all entries associated with a `Contentful.Space` __that are **published**__.
Will take basic collection filters into account, specifically `:limit` and `:skip` to traverse and
limit the collection of entries.
Will fetch a single page as defined by its params and will fetch it eagerly (calls the API immediately.).
## Examples
{:ok, [
%Entry{ sys: %{ id: "foobar_0"}},
%Entry{ sys: %{ id: "foobar_1"}},
%Entry{ sys: %{ id: "foobar_2"}}
], total: 3} = space |> Entries.fetch_all
{:ok, [
%Entry{ sys: %{ id: "foobar_1"}},
%Entry{ sys: %{ id: "foobar_2"}}
], total: 3} = space |> Entries.fetch_all(skip: 1)
{:ok, [
%Entry{ sys: %{ id: "foobar_0"}}
], total: 3} = space |> Entries.fetch_all(limit: 1)
{:ok, [
%Entry{ sys: %{ id: "foobar_2"}}
], total: 3} = space |> Entries.fetch_all(limit: 1, skip: 2)
"""
@impl Collection
@spec fetch_all(
list(keyword()),
Space.t() | String.t(),
String.t() | nil,
String.t() | nil
) ::
{:ok, list(Entry.t())}
| {:error, atom(), original_message: String.t()}
| {:error, :rate_limit_exceeded, wait_for: integer()}
| {:error, :unknown}
def fetch_all(
options \\ [],
space \\ Delivery.config(:space_id),
env \\ Delivery.config(:environment),
api_key \\ Delivery.config(:access_token)
)
def fetch_all(options, %Space{sys: %{id: space_id}}, env, api_key) do
space_id
|> build_multi_request(options, env, api_key)
|> Delivery.send_request()
|> Delivery.parse_response(&build_entries/1)
end
def fetch_all(options, space_id, env, api_key)
when is_binary(space_id) do
fetch_all(options, %Space{sys: %{id: space_id}}, env, api_key)
end
@doc """
Constructs a stream around __all entries__ of a `Contentful.Space` __that are published__.
Will return a stream of entries that can be composed with the standard libraries functions.
This function calls the API endpoint for entries on demand, e.g. until the upper limit
(the total of all entries) is reached.
__Warning__: With very large entry collections, this can quickly run into the request limit of the API!
## Examples
# uses the configured space for streaming
Entries.stream() |> Enum.take(1)
space = "my_space_id"
# API calls calculated by the stream (in this case two calls)
["first_entry_id", "second_entry_id"] =
Entries.stream([limit: 1], space)
|> Stream.map(fn %{ sys: %{ id: id }} -> id end)
|> Enum.take(2)
environment = "staging"
api_token = "foobar?foob4r"
["first_entry_id"] =
Entries.stream([limit: 1], space, environment, api_token)
|> Stream.map(fn %{ sys: %{ id: id }} -> id end)
|> Enum.take(2)
# Use the :limit parameter to set the page size
["first_entry_id", "second_entry_id", "third_entry_id", "fourth_entry_id"] =
Entries.stream([limit: 4], space)
|> Stream.map(fn %{ sys: %{ id: id }} -> id end)
|> Enum.take(4)
"""
@impl CollectionStream
def stream(
options \\ [],
space \\ Delivery.config(:space_id),
env \\ Delivery.config(:environment),
api_key \\ Delivery.config(:access_token)
) do
space |> CollectionStream.stream_all(&fetch_all/4, options, env, api_key)
end
defp build_single_request(space_id, entry_id, env, api_key) do
url = [
space_id |> Delivery.url(env),
"/entries/#{entry_id}"
]
{url, api_key |> Delivery.request_headers()}
end
defp build_multi_request(space, options, env, api_key) do
url = [
space |> Delivery.url(env),
"/entries",
options |> Delivery.collection_query_params()
]
{url, api_key |> Delivery.request_headers()}
end
defp build_entries(%{"total" => total, "items" => items}) do
entries =
items
|> Enum.map(&build_entry/1)
|> Enum.map(fn {:ok, entry} -> entry end)
{:ok, entries, total: total}
end
defp build_entry(%{
"fields" => fields,
"sys" => %{"id" => id, "revision" => rev}
}) do
{:ok,
%Entry{
fields: fields,
sys: %SysData{id: id, revision: rev}
}}
end
end