Turning gRPC failures into the %TypeDB.Error{} the sibling driver returns.
This module exists so that the two transports are interchangeable at the call
site. An application that routes failures by kind, by code, or through
TypeDB.Error.retryable?/1 keeps every branch it wrote when it switches, and
that is the whole reason typedb_grpc depends on typedb rather than
defining error types of its own.
Where a TypeDB error code lives on this transport
Nowhere obvious, which is why this is a module and not a function. A gRPC
failure arrives as a GRPC.RPCError whose message is a category
("Unauthenticated", "Request generated error") rather than anything about
the request. The useful parts are in details, as two google.rpc messages
that TypeDB attaches by hand:
ErrorInfo.reason— the TypeDB code,"AUT1","DBD1","STC2". The same codes the HTTP API puts in its JSON body.DebugInfo.stack_entries— the human messages, most specific first.
Measured against 3.12.1: deleting a database that does not exist arrives as
gRPC status 3 with reason: "DBD1" and stack entries
["[DBD1] Cannot delete database since it does not exist.", "[SRV13] Unable to delete database."].
Why :status carries an HTTP status on a transport that has none
%TypeDB.Error{} documents :status as the HTTP status, and there is no HTTP
here. It is filled anyway, with the standard gRPC-to-HTTP equivalence that
grpc-gateway and every other bridge uses, because TypeDB.Error.retryable?/1
judges :server errors by status — and a nil there would quietly make the
same failure retryable over one transport and terminal over the other. That
divergence is exactly what sharing the struct is meant to prevent.
The gRPC status is not lost: it is in :reason, as {:grpc_status, integer}.
Summary
Functions
Converts anything else a gRPC call can fail with.
Converts a GRPC.RPCError into a %TypeDB.Error{}.
The HTTP status this driver reports for a gRPC status code.
Functions
@spec from_reason(term(), String.t()) :: TypeDB.Error.t()
Converts anything else a gRPC call can fail with.
The adapter reports a connection that could not be established, or a stream
that died, as plain terms rather than as GRPC.RPCError. They are transport
failures in the sense %TypeDB.Error{} means: the request produced no answer,
and trying again could produce one.
@spec from_rpc_error(GRPC.RPCError.t(), String.t()) :: TypeDB.Error.t()
Converts a GRPC.RPCError into a %TypeDB.Error{}.
context is prepended to the message when the server gave nothing better —
it names the operation, so that a bare "Request generated error" still tells
the reader what was being attempted.
@spec http_status(integer()) :: pos_integer()
The HTTP status this driver reports for a gRPC status code.
iex> TypeDB.GRPC.Error.http_status(16)
401
iex> TypeDB.GRPC.Error.http_status(14)
503Unknown codes become 500: a gRPC status this driver has not seen is the
server behaving in a way nobody predicted, which is what 500 means.