lib/jsonapi_plug/document/jsonapi_object.ex

defmodule JSONAPIPlug.Document.JSONAPIObject do
  @moduledoc """
  JSON:API Document JSON:API Object
  """

  alias JSONAPIPlug.{Document, Exceptions.InvalidDocument}

  @type version :: :"1.0"

  @type t :: %__MODULE__{meta: Document.meta() | nil, version: version()}
  defstruct meta: nil, version: nil

  @spec deserialize(Document.payload()) :: t() | no_return()
  def deserialize(data) do
    %__MODULE__{}
    |> deserialize_meta(data)
    |> deserialize_version(data)
  end

  defp deserialize_meta(jsonapi_object, %{"meta" => meta}) when is_map(meta),
    do: %__MODULE__{jsonapi_object | meta: meta}

  defp deserialize_meta(_jsonapi_object, %{"meta" => _meta}) do
    raise InvalidDocument,
      message: "JSON:API object 'meta' must be an object",
      reference: "https://jsonapi.org/format/#document-jsonapi-object"
  end

  defp deserialize_meta(jsonapi_object, _data), do: jsonapi_object

  defp deserialize_version(jsonapi_object, %{"version" => "1.0"}),
    do: %__MODULE__{jsonapi_object | version: :"1.0"}

  defp deserialize_version(jsonapi_object, %{"version" => "1.1"}),
    do: %__MODULE__{jsonapi_object | version: :"1.1"}

  defp deserialize_version(_jsonapi_object, %{"version" => version}) do
    raise InvalidDocument,
      message: "JSON:API Object has invalid version (#{version})",
      reference: "https://jsonapi.org/format/#document-jsonapi-object"
  end

  defp deserialize_version(jsonapi_object, _data), do: jsonapi_object
end