Current section

Files

Jump to
dspace_ex lib dspace api transform.ex
Raw

lib/dspace/api/transform.ex

defmodule DSpace.API.Transform do
@moduledoc """
Functions for transforming API responses.
"""
import DSpace.Utils, only: [is_nonempty_binary: 1]
alias DSpace.API.HTTP.Response
@doc """
Extracts the body as a map from an API response structure.
"""
@spec from_response(Response.t() | term()) :: map()
def from_response(%Response{body: body}) when is_map(body), do: body
def from_response(_), do: %{}
@doc """
Extracts a value from the response body by key.
"""
@spec get(Response.t(), binary()) :: term()
def get(%Response{body: body}, key, default \\ nil) when is_map(body) and is_nonempty_binary(key) do
Map.get(body, key, default)
end
@doc """
Extracts and transforms a collection of resources from a response.
## Parameters
* `map` - A map or `t:DSpace.API.HTTP.Response.t/0` containing the resource(s)
* `options` - Keyword list of options
## Options
* `:extract` - A path to navigate to the resource(s) (defaults to `nil`)
* `:transform` - A function to process each resource (defaults to identity)
"""
@spec transform(Response.t() | map(), keyword()) :: list(term())
def transform(%Response{body: body}, options) when is_map(body), do: transform(body, options)
def transform(map, options) when is_map(map) and is_list(options) do
transform = Keyword.get(options, :transform, &Function.identity/1)
path = Keyword.get(options, :extract)
map
|> extract_resources(path)
|> Enum.map(transform)
end
@doc """
Extracts resources and metadata from a paginated collection response.
Returns a three-element tuple `{data, meta, next}`:
* `data` - List of transformed resources
* `meta` - Meta information from the API response
* `next` - URL for next page or nil if no more pages
## Parameters
* `map` - A map or `t:DSpace.API.HTTP.Response.t/0` containing the resource collection
* `options` - Keyword list of options
## Options
* `:extract` - A path to navigate to the resources (required)
* `:next` - A path to navigate to the continuation token
(defaults to `["_links", "next", "href"]`)
* `:transform` - A function to process each resource (defaults to identity)
"""
@spec transform_collection(struct() | map(), keyword()) :: {list(term()), map(), term()}
def transform_collection(%Response{body: body}, options) when is_map(body) do
transform_collection(body, options)
end
def transform_collection(map, options) when is_map(map) and is_list(options) do
extract_path = Keyword.fetch!(options, :extract)
next_path = Keyword.get(options, :next, ["_links", "next", "href"])
transform = Keyword.get(options, :transform, &Function.identity/1)
data =
map
|> extract_resources(extract_path)
|> Enum.map(transform)
next = get_in(map, next_path)
meta = drop_extracted(map, extract_path)
{data, meta, next}
end
# Private helpers
defp extract_resources(map, nil), do: [map]
defp extract_resources(map, path) when is_list(path), do: get_in(map, path) || []
defp drop_extracted(map, path) when is_list(path) do
[first_key | _rest] = path
Map.delete(map, first_key)
end
end