defmodule Twirp.Error do @moduledoc """ This module defines the different error codes as specified in https://twitchtv.github.io/twirp/docs/spec_v5.html#error-codes. We provide a function for each error code to that its easy for users to return errors in their handlers. """ @error_code_to_http_status %{ # RequestTimeout canceled: 408, # BadRequest invalid_argument: 400, # RequestTimeout deadline_exceeded: 408, # Not Found not_found: 404, # Not Found bad_route: 404, # Conflict already_exists: 409, # Forbidden permission_denied: 403, # Unauthorized unauthenticated: 401, # Forbidden resource_exhausted: 403, # Precondition Failed failed_precondition: 412, # Conflict aborted: 409, # Bad Request out_of_range: 400, # Internal Server Error internal: 500, # Internal Server Error unknown: 500, # Not Implemented unimplemented: 501, # Service Unavailable unavailable: 503, # Internal Server Error data_loss: 500 } @error_codes Map.keys(@error_code_to_http_status) @error_code_strings for code <- @error_codes, do: Atom.to_string(code) defexception ~w|code msg meta|a @type t :: %__MODULE__{ code: atom(), msg: binary(), meta: %{atom() => binary()} } for code <- @error_codes do def unquote(code)(msg, meta \\ []) do new(unquote(code), msg, meta) end end def valid_code?(code) when is_atom(code), do: code in @error_codes def valid_code?(code) when is_binary(code), do: code in @error_code_strings def code_to_status(code) when code in @error_codes do @error_code_to_http_status[code] end def new(code, msg, meta \\ []) do %__MODULE__{code: code, msg: msg, meta: Enum.into(meta, %{})} end @impl true def message(%__MODULE__{msg: msg}), do: msg defimpl Jason.Encoder do def encode(struct, opts) do map = if struct.meta == %{} do Map.take(struct, [:code, :msg]) else Map.take(struct, [:code, :msg, :meta]) end Jason.Encode.map(map, opts) end end end