diff --git a/lib/grpc/server.ex b/lib/grpc/server.ex index f1bacb68..0307e88a 100644 --- a/lib/grpc/server.ex +++ b/lib/grpc/server.ex @@ -184,12 +184,16 @@ defmodule GRPC.Server do ) do GRPC.Telemetry.server_span(server, endpoint, func_name, stream, fn -> last = fn r, s -> - reply = apply(server, func_name, [r, s]) - - if res_stream do - {:ok, stream} - else - {:ok, stream, reply} + case apply(server, func_name, [r, s]) do + %GRPC.RPCError{} = error -> + {:error, error} + + reply -> + if res_stream do + {:ok, stream} + else + {:ok, stream, reply} + end end end diff --git a/lib/grpc/server/adapters/cowboy/handler.ex b/lib/grpc/server/adapters/cowboy/handler.ex index f0f5641b..ce9c03ca 100644 --- a/lib/grpc/server/adapters/cowboy/handler.ex +++ b/lib/grpc/server/adapters/cowboy/handler.ex @@ -347,11 +347,8 @@ defmodule GRPC.Server.Adapters.Cowboy.Handler do result = try do case do_call_rpc(server, path, stream) do - {:error, _} = err -> - err - - _ -> - :ok + {:error, _} = err -> err + _ -> :ok end catch kind, e -> @@ -361,14 +358,8 @@ defmodule GRPC.Server.Adapters.Cowboy.Handler do end case result do - {:error, %GRPC.RPCError{} = e} -> - exit({e, ""}) - - {:error, %{kind: kind}} -> - exit({:handle_error, kind}) - - other -> - other + {:error, %GRPC.RPCError{} = e} -> exit({e, ""}) + :ok -> :ok end end @@ -387,8 +378,11 @@ defmodule GRPC.Server.Adapters.Cowboy.Handler do GRPC.Server.send_trailers(stream, @default_trailers) {:ok, stream} - error -> - error + {:error, error = %GRPC.RPCError{message: nil, status: status}} -> + {:error, %{error | message: GRPC.Status.status_message(status)}} + + {:error, error = %GRPC.RPCError{}} -> + {:error, error} end end @@ -422,7 +416,7 @@ defmodule GRPC.Server.Adapters.Cowboy.Handler do :cowboy_req.reply(200, trailers, req) end - def exit_handler(pid, reason) do + defp exit_handler(pid, reason) do if Process.alive?(pid) do Process.exit(pid, reason) end diff --git a/test/grpc/integration/server_test.exs b/test/grpc/integration/server_test.exs index 378a6754..810cec85 100644 --- a/test/grpc/integration/server_test.exs +++ b/test/grpc/integration/server_test.exs @@ -60,6 +60,19 @@ defmodule GRPC.Integration.ServerTest do raise "unknown error(This is a test, please ignore it)" end + def say_hello(%{name: "handled error"}, _stream) do + %GRPC.RPCError{ + status: GRPC.Status.unauthenticated(), + message: "Please authenticate" + } + end + + def say_hello(%{name: "handled error without message"}, _stream) do + %GRPC.RPCError{ + status: GRPC.Status.unauthenticated() + } + end + def say_hello(_req, _stream) do raise GRPC.RPCError, status: GRPC.Status.unauthenticated(), message: "Please authenticate" end @@ -172,6 +185,33 @@ defmodule GRPC.Integration.ServerTest do end) end + test "return errors for handled errors" do + run_server([HelloErrorServer], fn port -> + {:ok, channel} = GRPC.Stub.connect("localhost:#{port}") + req = Helloworld.HelloRequest.new(name: "handled error") + {:error, reply} = channel |> Helloworld.Greeter.Stub.say_hello(req) + + assert %GRPC.RPCError{ + status: GRPC.Status.unauthenticated(), + message: "Please authenticate" + } == reply + end) + end + + test "return errors for handled errors with the default message of the status" do + run_server([HelloErrorServer], fn port -> + {:ok, channel} = GRPC.Stub.connect("localhost:#{port}") + req = Helloworld.HelloRequest.new(name: "handled error without message") + {:error, reply} = channel |> Helloworld.Greeter.Stub.say_hello(req) + + assert %GRPC.RPCError{ + status: GRPC.Status.unauthenticated(), + message: + "The request does not have valid authentication credentials for the operation" + } == reply + end) + end + test "returns appropriate error for stream requests" do run_server([FeatureErrorServer], fn port -> {:ok, channel} = GRPC.Stub.connect("localhost:#{port}")