Current section
Files
Jump to
Current section
Files
lib/retort/response/error.ex
defmodule Retort.Response.Error do
@moduledoc """
A JSON-RPC [Response Error object](http://www.jsonrpc.org/specification#error_object)
"""
alias Alembic.{Document, Source}
# Struct
defstruct code: nil,
message: nil,
data: nil
# Types
@type t :: %__MODULE__{
code: integer,
message: String.t,
data: term
}
# Functions
@doc """
Uses rendered `changset` as data for error.
"""
@spec from_changeset(Ecto.Changeset.t, (Ecto.Changeset.t -> map)):: t
def from_changeset(changeset = %Ecto.Changeset{}, render) when is_function(render, 1) do
"Changeset error"
|> predefined
|> struct(data: render.(changeset))
end
@doc """
Uses JSON API `document` as data for error. Only use when the `document` is a JSON API errors document.
"""
@spec from_document(Document.t) :: t
def from_document(document = %Document{errors: errors}) when is_list(errors) do
"JSONAPI error"
|> predefined
|> struct(data: document)
end
@doc """
Converts JSON decoded map with `String.t` keys to `t`.
# From error with data
iex> Retort.Response.Error.from_json(%{"code" => 0, "data" => "Data", "message" => "Zero"})
%Retort.Response.Error{code: 0, data: "Data", message: "Zero"}
# From error without data
iex> Retort.Response.Error.from_json(%{"code" => 0, "message" => "Zero"})
%Retort.Response.Error{code: 0, data: nil, message: "Zero"}
"""
@spec from_json(%{required(binary) => integer, required(binary) => binary, optional(term) => term}) :: t
def from_json(json = %{"code" => code, "message" => message}) when is_integer(code) and is_binary(message) do
%__MODULE__{
code: code,
# data is optional
data: data_from_json(json["data"]),
message: message
}
end
@code_by_message %{
"Changeset error" => 422,
"Internal error" => -32_603,
"Invalid params" => -32_602,
"Invalid Request" => -32_600,
"JSONAPI error" => 422,
"Method not found" => -32_601,
"Parse error" => -32_700
}
@doc """
Looks up [predefined](http://www.jsonrpc.org/specification#error_object) `t`.
"""
@spec predefined(String.t) :: t
for {message, code} <- @code_by_message do
def predefined(unquote(message)) do
%__MODULE__{
code: unquote(code),
message: unquote(message)
}
end
end
## Private Functions
defp data_from_json(json) do
case Document.from_json(
json,
%Alembic.Error{
source: %Source{
pointer: ""
}
}
) do
{:ok, document} ->
document
_ ->
json
end
end
end