diff --git a/context/getting-started.md b/context/getting-started.md index 8e12834..1adb5e9 100644 --- a/context/getting-started.md +++ b/context/getting-started.md @@ -18,7 +18,7 @@ $ bundle add protocol-grpc - A {ruby Protocol::GRPC::Body::Readable} class which handles reading gRPC messages from HTTP request/response bodies with automatic framing and decoding. - A {ruby Protocol::GRPC::Body::Writable} class which handles writing gRPC messages to HTTP request/response bodies with automatic framing and encoding. - A {ruby Protocol::GRPC::Middleware} abstract base class for building gRPC server applications. - - A {ruby Protocol::GRPC::Call} class which represents the context of a single gRPC RPC call, including deadline tracking. + - A {ruby Protocol::GRPC::Call} class which represents the request, response, metadata, and deadline for a single gRPC RPC call. - A {ruby Protocol::GRPC::Status} module with gRPC status code constants. - A {ruby Protocol::GRPC::Error} hierarchy for gRPC-specific error handling. @@ -132,13 +132,14 @@ end ``` ruby require "protocol/grpc/call" -call = Protocol::GRPC::Call.new(request, deadline: deadline) +call = Protocol::GRPC::Call.new(request, response, deadline: deadline) # Access request call.request # => Protocol::HTTP::Request -# Check deadline +# Check deadline and status call.deadline.exceeded? # => false +call.status # => Protocol::GRPC::Status::OK # Access peer information call.peer # => Protocol::HTTP::Address diff --git a/guides/getting-started/readme.md b/guides/getting-started/readme.md index 8e12834..1adb5e9 100644 --- a/guides/getting-started/readme.md +++ b/guides/getting-started/readme.md @@ -18,7 +18,7 @@ $ bundle add protocol-grpc - A {ruby Protocol::GRPC::Body::Readable} class which handles reading gRPC messages from HTTP request/response bodies with automatic framing and decoding. - A {ruby Protocol::GRPC::Body::Writable} class which handles writing gRPC messages to HTTP request/response bodies with automatic framing and encoding. - A {ruby Protocol::GRPC::Middleware} abstract base class for building gRPC server applications. - - A {ruby Protocol::GRPC::Call} class which represents the context of a single gRPC RPC call, including deadline tracking. + - A {ruby Protocol::GRPC::Call} class which represents the request, response, metadata, and deadline for a single gRPC RPC call. - A {ruby Protocol::GRPC::Status} module with gRPC status code constants. - A {ruby Protocol::GRPC::Error} hierarchy for gRPC-specific error handling. @@ -132,13 +132,14 @@ end ``` ruby require "protocol/grpc/call" -call = Protocol::GRPC::Call.new(request, deadline: deadline) +call = Protocol::GRPC::Call.new(request, response, deadline: deadline) # Access request call.request # => Protocol::HTTP::Request -# Check deadline +# Check deadline and status call.deadline.exceeded? # => false +call.status # => Protocol::GRPC::Status::OK # Access peer information call.peer # => Protocol::HTTP::Address diff --git a/lib/protocol/grpc/call.rb b/lib/protocol/grpc/call.rb index cbcd0d7..1c73d69 100644 --- a/lib/protocol/grpc/call.rb +++ b/lib/protocol/grpc/call.rb @@ -66,6 +66,14 @@ def time_remaining @deadline&.remaining end + # Get the current gRPC status of the call. + # @returns [Integer | Nil] The current gRPC status code, if available. + def status + if headers = @response&.headers + headers["grpc-status"]&.to_i + end + end + # Get peer information (client address). # @returns [String | Nil] The peer address as a string, or `Nil` if not available def peer diff --git a/releases.md b/releases.md index 3386aa5..2976ec4 100644 --- a/releases.md +++ b/releases.md @@ -3,6 +3,7 @@ ## Unreleased - **Breaking**: Removed the unused `Protocol::GRPC::Call#cancel!` and `Protocol::GRPC::Call#cancelled?` methods. + - Added `Protocol::GRPC::Call#status` to report the status assigned to the response. ## v0.13.1 diff --git a/test/protocol/grpc/call.rb b/test/protocol/grpc/call.rb index 08ef9b1..a5d261f 100644 --- a/test/protocol/grpc/call.rb +++ b/test/protocol/grpc/call.rb @@ -10,7 +10,8 @@ describe Protocol::GRPC::Call do let(:headers) {Protocol::HTTP::Headers.new([["authorization", "Bearer token123"]])} let(:request) {Protocol::HTTP::Request.new("https", "localhost", "POST", "/service/method", nil, headers, nil)} - let(:response) {Protocol::HTTP::Response[200, {}, []]} + let(:response_headers) {Protocol::HTTP::Headers.new(policy: Protocol::GRPC::HEADER_POLICY)} + let(:response) {Protocol::HTTP::Response[200, response_headers, []]} with ".for" do it "creates a call with request and response" do @@ -63,6 +64,27 @@ end end + with "status" do + it "returns the status assigned to the response" do + Protocol::GRPC::Metadata.assign_status!(response.headers, status: Protocol::GRPC::Status::RESOURCE_EXHAUSTED) + call = subject.new(request, response) + + expect(call.status).to be == Protocol::GRPC::Status::RESOURCE_EXHAUSTED + end + + it "returns nil without an assigned response status" do + call = subject.new(request, response) + + expect(call.status).to be_nil + end + + it "returns nil without a response" do + call = subject.new(request) + + expect(call.status).to be_nil + end + end + with "deadline" do let(:deadline) {Async::Deadline.start(5.0)}