Packages
gRPC client implementation for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/grpc/rpc_error.ex
defmodule GRPC.RPCError do
@moduledoc """
The RPC error raised in server side and got in client side.
# server side
raise GRPC.RPCError, status: :unknown # preferred
raise GRPC.RPCError, status: GRPC.Status.unknown, message: "error message"
# client side
{:error, error} = Your.Stub.unary_call(channel, request)
Error handling can be done with the `is_rpc_error/2` guard.
Expanding on the code above, the first option is for the guard to
be used in a `cond` or `case`, as follows:
cond do
is_rpc_error(error, GRPC.Status.not_found()) ->
do_something_when_not_found()
is_rpc_error(error, GRPC.Status.out_of_range()) ->
do_something_when_out_of_range()
true ->
fallback_code()
end
Another option is for the error handling to be written into a multi-clause function.
In such case we must define module attributes for each of the errors we want because
the functions in `GRPC.Status` can't be called directly inside the guard.
...
handle_error(error)
...
@not_found GRPC.Status.not_found()
@out_of_range GRPC.Status.out_of_range()
defp handle_error(error) when is_rpc_error(error, @not_found) do
# not found
end
defp handle_error(error) when is_rpc_error(error, @out_of_range) do
# out of range
end
defp handle_error(error) do
# fallback
end
See `GRPC.Status` for more details on possible statuses.
"""
defexception [:status, :message]
defguard is_rpc_error(e, status) when is_struct(e, __MODULE__) and e.status == status
@type t :: %__MODULE__{status: GRPC.Status.t(), message: String.t()}
alias GRPC.Status
@spec new(status :: atom()) :: t()
def new(status) when is_atom(status) do
exception(status: status)
end
@spec exception(args :: list()) :: t()
def exception(args) when is_list(args) do
error = parse_args(args, %__MODULE__{})
%{error | message: error.message || Status.status_message(error.status)}
end
defp parse_args([], acc), do: acc
defp parse_args([{:status, status} | t], acc) when is_integer(status) do
acc = %{acc | status: status}
parse_args(t, acc)
end
defp parse_args([{:status, status} | t], acc) when is_atom(status) do
acc = %{acc | status: apply(GRPC.Status, status, [])}
parse_args(t, acc)
end
defp parse_args([{:message, message} | t], acc) when is_binary(message) do
acc = %{acc | message: message}
parse_args(t, acc)
end
@spec exception(status :: Status.t() | atom(), message :: String.t()) :: t()
def exception(status, message) when is_atom(status) do
%GRPC.RPCError{status: apply(GRPC.Status, status, []), message: message}
end
def exception(status, message) when is_integer(status) do
%GRPC.RPCError{status: status, message: message}
end
end