Current section
Files
Jump to
Current section
Files
lib/ghost_content.ex
defmodule GhostContent do
@moduledoc """
An Elixir client for the Ghost publishing platform's Content API.
Full documentation of the Ghost Content API is available at:
https://ghost.org/docs/content-api/
"""
@type config() :: [api_key: String.t(), host: String.t()]
@type options() :: [
filter: String.t() | nil,
include: String.t() | nil,
page: String.t() | nil,
limit: String.t() | nil,
order: String.t() | nil,
fields: String.t() | nil
]
@type meta() :: %{
next: String.t() | nil,
prev: String.t() | nil,
total: integer(),
limit: integer(),
pages: integer(),
page: integer()
}
alias GhostContent.{Author, Post, Tag}
@doc """
Loads a configuration for use in subsequent API calls.
"""
@spec config(atom()) :: config()
def config(otp_app) do
Application.get_env(otp_app, :ghost_content)
end
@doc """
Gets a list of posts.
Accepts the following options:
`limit, page, filter, order, fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#posts
"""
@spec get_posts(config(), options() | nil) :: {:ok, %{meta: meta(), posts: [Post.t()]}}
def get_posts(config, opts \\ []) do
case perform_request(config, "/ghost/api/content/posts/", opts) do
{:ok, r = %{posts: posts}} ->
{:ok, %{r | posts: Enum.map(posts, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single post by ID.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#posts
"""
@spec get_post(config(), String.t(), options() | nil) :: {:ok, %{posts: [Post.t()]}}
def get_post(config, id, opts \\ []) do
case perform_request(config, "/ghost/api/content/posts/#{id}/", opts) do
{:ok, r = %{posts: posts}} ->
{:ok, %{r | posts: Enum.map(posts, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single post by Slug.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#posts
"""
@spec get_post_by_slug(config(), String.t(), options() | nil) :: {:ok, %{posts: [Post.t()]}}
def get_post_by_slug(config, slug, opts \\ []) do
case perform_request(config, "/ghost/api/content/posts/slug/#{slug}/", opts) do
{:ok, r = %{posts: posts}} ->
{:ok, %{r | posts: Enum.map(posts, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a list of pages.
Accepts the following options:
`limit, page, filter, order, fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#pages
"""
@spec get_pages(config(), options() | nil) :: {:ok, %{pages: [Post.t()]}}
def get_pages(config, opts \\ []) do
case perform_request(config, "/ghost/api/content/pages/", opts) do
{:ok, r = %{pages: pages}} ->
{:ok, %{r | pages: Enum.map(pages, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single page by ID.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#pages
"""
@spec get_page(config(), String.t(), options() | nil) :: {:ok, %{pages: [Post.t()]}}
def get_page(config, id, opts \\ []) do
case perform_request(config, "/ghost/api/content/pages/#{id}/", opts) do
{:ok, r = %{pages: pages}} ->
{:ok, %{r | pages: Enum.map(pages, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single page by Slug.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#pages
"""
@spec get_page_by_slug(config(), String.t(), options() | nil) :: {:ok, %{pages: [Post.t()]}}
def get_page_by_slug(config, slug, opts \\ []) do
case perform_request(config, "/ghost/api/content/pages/slug/#{slug}/", opts) do
{:ok, r = %{pages: pages}} ->
{:ok, %{r | pages: Enum.map(pages, &Post.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a list of authors.
Accepts the following options:
`limit, page, filter, order, fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#authors
"""
@spec get_authors(config(), options() | nil) :: {:ok, %{authors: [Author.t()]}}
def get_authors(config, opts \\ []) do
case perform_request(config, "/ghost/api/content/authors/", opts) do
{:ok, r = %{authors: authors}} ->
{:ok, %{r | authors: Enum.map(authors, &Author.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single author by ID.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#authors
"""
@spec get_author(config(), String.t(), options() | nil) :: {:ok, %{authors: [Author.t()]}}
def get_author(config, id, opts \\ []) do
case perform_request(config, "/ghost/api/content/authors/#{id}/", opts) do
{:ok, r = %{authors: authors}} ->
{:ok, %{r | authors: Enum.map(authors, &Author.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single author by Slug.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#authors
"""
@spec get_author_by_slug(config(), String.t(), options() | nil) ::
{:ok, %{authors: [Author.t()]}}
def get_author_by_slug(config, slug, opts \\ []) do
case perform_request(config, "/ghost/api/content/authors/slug/#{slug}/", opts) do
{:ok, r = %{authors: authors}} ->
{:ok, %{r | authors: Enum.map(authors, &Author.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a list of tags.
Accepts the following options:
`limit, page, filter, order, fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#tags
"""
@spec get_tags(config(), options() | nil) :: {:ok, %{tags: [Tag.t()]}}
def get_tags(config, opts \\ []) do
case perform_request(config, "/ghost/api/content/tags/", opts) do
{:ok, r = %{tags: tags}} ->
{:ok, %{r | tags: Enum.map(tags, &Tag.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single tag by ID.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#tags
"""
@spec get_tag(config(), String.t(), options() | nil) :: {:ok, %{tags: [Tag.t()]}}
def get_tag(config, id, opts \\ []) do
case perform_request(config, "/ghost/api/content/tags/#{id}/", opts) do
{:ok, r = %{tags: tags}} ->
{:ok, %{r | tags: Enum.map(tags, &Tag.from_map!/1)}}
e ->
e
end
end
@doc """
Gets a single tag by Slug.
Accepts the following options:
`fields, include`
For exact usage, see: https://ghost.org/docs/content-api/#tags
"""
@spec get_tag_by_slug(config(), String.t(), options() | nil) :: {:ok, %{tags: [Tag.t()]}}
def get_tag_by_slug(config, slug, opts \\ []) do
case perform_request(config, "/ghost/api/content/tags/slug/#{slug}/", opts) do
{:ok, r = %{tags: tags}} ->
{:ok, %{r | tags: Enum.map(tags, &Tag.from_map!/1)}}
e ->
e
end
end
defp perform_request(config, path, opts) do
params =
%{
limit: Keyword.get(opts, :limit, 15),
page: Keyword.get(opts, :page, 1),
filter: Keyword.get(opts, :filter, nil),
order: Keyword.get(opts, :order, nil),
fields: Keyword.get(opts, :fields, nil),
include: Keyword.get(opts, :include, nil)
}
|> Enum.reduce(%{}, fn
{_, nil}, a -> a
{k, v}, a -> Map.put(a, k, v)
end)
uri_string =
"#{config[:host]}#{path}"
|> URI.parse()
|> Map.put(:query, URI.encode_query(Map.merge(params, %{key: config[:api_key]})))
|> URI.to_string()
with {:ok, response = %HTTPoison.Response{status_code: 200}} <-
HTTPoison.get(uri_string),
{:ok, data} <- Jason.decode(response.body, keys: :atoms) do
{:ok, data}
else
{_, result} -> {:error, result}
end
end
end