Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monkey patch gruf interceptor #17

Merged
merged 10 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,22 @@ service MyService {

## Gruf Interceptors

grpc-rest supports [gruf](https://github.com/bigcommerce/gruf) Interceptors. As long as you're not using a custom interceptor
grpc-rest supports [gruf](https://github.com/bigcommerce/gruf) Interceptors through a custom `GrpcRest::BaseInterceptor` class. As long as you're not using a custom interceptor
registry, your interceptors will be called normally around the controller.

```ruby
module Interceptors
# Interceptor for catching errors from controllers
class ErrorInterceptor < GrpcRest::BaseInterceptor

def call
# Your code here
end

end
end
```

## To Do

* Replace Go implementation with Ruby (+ executable)
Expand Down
46 changes: 46 additions & 0 deletions lib/base_interceptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

require 'gruf'

module GrpcRest
# This is a monkey-patch that fixes an issue we were having with using the fail! method in
# interceptors where an active call was not instantiated yet.
# Basically, we overloaded this function: https://github.com/bigcommerce/gruf/blob/main/lib/gruf/errors/helpers.rb#L34
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change this comment to:

Fixes an issue with the fail! method since the active call is not instantiated yet.
Overloads https://github.com/bigcommerce/gruf/blob/main/lib/gruf/errors/helpers.rb#L34

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, less filler words. 👍

class BaseInterceptor < ::Gruf::Interceptors::ServerInterceptor
def fail!(error_code, message = 'unknown error', metadata = {})
raise grpc_error(error_code, message.to_s, metadata)
end

private

# Ported from https://github.com/flipp-oss/grpc-rest/blob/main/lib/grpc_rest.rb#L142
def grpc_error(error_code, message, metadata)
case error_code
nkadovic marked this conversation as resolved.
Show resolved Hide resolved
when :ok
GRPC::Ok.new(message, metadata)
when 499
GRPC::Cancelled.new(message, metadata)
when :bad_request, :invalid_argument
GRPC::InvalidArgument.new(message, metadata)
when :gateway_timeout
GRPC::DeadlineExceeded.new(message, metadata)
when :not_found
GRPC::NotFound.new(message, metadata)
when :conflict
GRPC::AlreadyExists.new(message, metadata)
when :forbidden
GRPC::PermissionDenied.new(message, metadata)
when :unauthorized
GRPC::Unauthenticated.new(message, metadata)
when :too_many_requests
GRPC::ResourceExhausted.new(message, metadata)
when :not_implemented
GRPC::Unimplemented.new(message, metadata)
when :service_unavailable
GRPC::Unavailable.new(message, metadata)
else
GRPC::Internal.new(message, metadata)
end
end
end
end
30 changes: 30 additions & 0 deletions spec/base_interceptor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

require_relative './spec_helper'
require 'src/proto/grpc/testing/test_services_pb'

RSpec.describe GrpcRest::BaseInterceptor, type: :class do
let(:rpc_service) { Grpc::Testing::TestService::Service.new }
let(:rpc_desc) { Grpc::Testing::TestService::Service.rpc_descs.values.first}
let(:message) { Grpc::Testing::SimpleRequest.new }

describe '#fail!' do
let(:error_message) { 'some message' }
let(:error_code) { :invalid_argument }

it 'fails properly' do
request = Gruf::Controllers::Request.new(
method_key: :UnaryCall,
service: rpc_service,
rpc_desc: rpc_desc,
active_call: nil,
message: message)
interceptor = GrpcRest::BaseInterceptor.new(request, Gruf::Error.new)

expect{ interceptor.fail!(error_code, error_message) }.to raise_error(GRPC::InvalidArgument) do |error|
expect(error.message).to match(error_message)
expect(error.code).to eq(GRPC::Core::StatusCodes::INVALID_ARGUMENT)
end
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class GrpcApp < Rails::Application
loader.ignore("#{Rails.root}/spec/test_service_pb.rb")
loader.setup
require "#{Rails.root}/spec/test_service_pb.rb"
require "#{Rails.root}/lib/base_interceptor.rb"
Copy link
Contributor Author

@nkadovic nkadovic Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this was the right way of fixing it, but I had to include this so my tests could properly run on the CI.


$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))

Expand Down
Loading