grpc-rest 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8debc27710d5f67910234915d93e7bd9f05cb5d1e58c58c5095b0f52a0ebd5ed
4
- data.tar.gz: ce3c4bfc2867bcf8b4b7bd46414b13420a6422d4195798925effc2937c27a3b2
3
+ metadata.gz: 628c8c0d79cbe90cfcb02c74d1f4e785ed25d7d56267bd1da54d4fe911ba0daa
4
+ data.tar.gz: a14292a527e3b1ae8c3455b3146c5aa9d3760d4cb11c5a1f206bba22e7690a67
5
5
  SHA512:
6
- metadata.gz: 8f42517bdc9bf2ddc7cdac30f24aee1b350f5adcb70449e714e75e661237709af10a3ad95df3c8736e429167de87997ccf3d6059599af903fe372d7ff49b2fc7
7
- data.tar.gz: 2ec236acb2c9e9b25f6ac0caeb309988434dc4269d66812928de885b2d1527d17dfe5a9c05bff4d53847cd8823257f98309d5d6700a1fb23e1083a868d9d7c03
6
+ metadata.gz: 64227c2f740fd93e1f9c1bcb3e4779fac6de80c47c5f85848b1ab785a5cde39347a03eee6184ab906937eac465ef40e601adcf0c625aeae97128440d9f8f6c55
7
+ data.tar.gz: 7c1a0b6bdc6f7d56380646b388fc8eca4755ad750d6a4054d1151d0052e2b661a2dafa4299b72cf883a7dc15fc71b0892fa166c64513b2c28d7f806010110cf6
data/CHANGELOG CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ # 0.3.0 - 2025-06-11
11
+
12
+ - Feature: Add `strict_mode` configuration for rejecting invalid JSON fields.
13
+ - Fixes for test failures that were caused by changes in 0.2.0 - test files weren't correctly regenerated.
14
+
10
15
  # 0.2.1 - 2025-05-06
11
16
  - Fix: Use `Array.wrap` to prevent grpc-rest from crashing when query parameters don't have `[]` suffixed.
12
17
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grpc-rest (0.2.0)
4
+ grpc-rest (0.2.1)
5
5
  google-protobuf (>= 4.30.2)
6
6
  grpc
7
7
  rails (>= 6.0)
data/README.md CHANGED
@@ -175,6 +175,14 @@ module Interceptors
175
175
  end
176
176
  ```
177
177
 
178
+ ### Configuration
179
+
180
+ GrpcRest currently has one configuration option, `strict_mode`, which defaults to false. When set to true, any JSON request that includes an unknown field will be rejected.
181
+
182
+ ```ruby
183
+ GrpcRest.strict_mode = true
184
+ ```
185
+
178
186
  ## Contributing
179
187
 
180
188
  Bug reports and pull requests are welcome on GitHub at https://github.com/flipp-oss/grpc-rest.
@@ -182,7 +190,13 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/flipp-
182
190
  To regenerate Ruby protobuf code for tests, install the `grpc-tools` gem and run this from the base directory:
183
191
 
184
192
  ```
185
- grpc_tools_ruby_protoc -I=./protoc-gen-rails/testdata --proto_path=./protoc-gen-rails/google-deps --ruby_out=./spec --grpc_out=./spec ./protoc-gen-rails/testdata/test_service.proto
193
+ grpc_tools_ruby_protoc -I=./spec/testdata --proto_path=./spec/google-deps --ruby_out=./spec --grpc_out=./spec ./spec/testdata/test_service.proto
194
+ ```
195
+
196
+ To regenerate the controller and route files for tests, run:
197
+
198
+ ```
199
+ bundle exec grpc_tools_ruby_protoc -I=./spec/testdata --proto_path=./spec/google-deps --rails_out=spec/testdata/base --rails_opt=require=spec/gen ./spec/testdata/test_service.proto
186
200
  ```
187
201
 
188
202
  ## License
@@ -17,9 +17,9 @@ class <%= service.name.demodulize %>Controller < ActionController::Base
17
17
 
18
18
  <% service.methods.each do |method| %>
19
19
  def <%= method.name %>
20
- fields = <%= method.request_type %>.descriptor.to_a.map(&:name)
21
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
22
- grpc_request = GrpcRest.init_request(<%= method.request_type %>, parameters.slice(*fields))
20
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
21
+ except(*%w(controller action <%= service.name.underscore %>))
22
+ grpc_request = GrpcRest.init_request(<%= method.request_type %>, parameters)
23
23
  GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["<%= method.name.underscore %>"], "<%= method.option_body %>", request.parameters)
24
24
  render json: GrpcRest.send_request("<%= service.namespace %>::<%= service.name.classify %>", "<%= method.name.underscore %>", grpc_request, <%= method.rest_options.inspect %>)
25
25
  end
@@ -82,7 +82,7 @@ module ProtocGenRails
82
82
  val = ''
83
83
  equal = name.index('=')
84
84
  if equal
85
- val = name[equal..]
85
+ val = name[equal+1..]
86
86
  name = name[0..equal - 1]
87
87
  end
88
88
  PathInfo.new(
data/lib/generator.rb CHANGED
@@ -14,7 +14,6 @@ module ProtocGenRails
14
14
  FileResult = Struct.new(:name, :content)
15
15
 
16
16
  class << self
17
-
18
17
  # @param params [String]
19
18
  def require_directories(params)
20
19
  params.split(',').each do |param|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrpcRest
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/grpc_rest.rb CHANGED
@@ -6,6 +6,8 @@ require 'grpc/core/status_codes'
6
6
 
7
7
  module GrpcRest
8
8
  class << self
9
+ attr_accessor :strict_mode
10
+
9
11
  def underscore(s)
10
12
  GRPC::GenericService.underscore(s)
11
13
  end
@@ -110,13 +112,16 @@ module GrpcRest
110
112
  end
111
113
  end
112
114
 
113
-
114
115
  params
115
116
  end
116
117
 
117
118
  def init_request(request_class, params)
118
119
  map_proto_record(request_class.descriptor, params)
119
- request_class.decode_json(JSON.generate(params), ignore_unknown_fields: true)
120
+ if GrpcRest.strict_mode
121
+ request_class.decode_json(JSON.generate(params))
122
+ else
123
+ request_class.decode_json(JSON.generate(params), ignore_unknown_fields: true)
124
+ end
120
125
  end
121
126
 
122
127
  def assign_params(request, param_hash, body_string, params)
@@ -14,7 +14,7 @@ class MyServiceController < ActionController::Base
14
14
  rescue_from ActionDispatch::Http::Parameters::ParseError, Google::Protobuf::TypeError do |e|
15
15
  render json: GrpcRest.error_msg(e), status: :bad_request
16
16
  end
17
- METHOD_PARAM_MAP = {"test"=>[{:name=>"foobar", :val=>"=blah/*", :split_name=>["foobar"]}],
17
+ METHOD_PARAM_MAP = {"test"=>[{:name=>"foobar", :val=>"blah/*", :split_name=>["foobar"]}],
18
18
  "test2"=>[],
19
19
  "test3"=>
20
20
  [{:name=>"sub_record.sub_id",
@@ -25,33 +25,33 @@ class MyServiceController < ActionController::Base
25
25
 
26
26
 
27
27
  def test
28
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
29
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
30
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
28
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
29
+ except(*%w(controller action my_service))
30
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
31
31
  GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test"], "", request.parameters)
32
32
  render json: GrpcRest.send_request("Testdata::MyService", "test", grpc_request, {:emit_defaults=>true})
33
33
  end
34
34
 
35
35
  def test2
36
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
37
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
38
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
36
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
37
+ except(*%w(controller action my_service))
38
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
39
39
  GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test2"], "second_record", request.parameters)
40
40
  render json: GrpcRest.send_request("Testdata::MyService", "test2", grpc_request, {})
41
41
  end
42
42
 
43
43
  def test3
44
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
45
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
46
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
44
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
45
+ except(*%w(controller action my_service))
46
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
47
47
  GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test3"], "", request.parameters)
48
48
  render json: GrpcRest.send_request("Testdata::MyService", "test3", grpc_request, {})
49
49
  end
50
50
 
51
51
  def test4
52
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
53
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
54
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
52
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
53
+ except(*%w(controller action my_service))
54
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
55
55
  GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test4"], "*", request.parameters)
56
56
  render json: GrpcRest.send_request("Testdata::MyService", "test4", grpc_request, {})
57
57
  end
@@ -10,15 +10,15 @@ class ServerImpl < Testdata::MyService::Service
10
10
  Testdata::TestResponse.new(some_int: 1, full_response: req.to_json)
11
11
  end
12
12
 
13
- def test_2(req)
13
+ def test2(req)
14
14
  Testdata::TestResponse.new(some_int: 2, full_response: req.to_json)
15
15
  end
16
16
 
17
- def test_3(req)
17
+ def test3(req)
18
18
  Testdata::TestResponse.new(some_int: 3, full_response: req.to_json)
19
19
  end
20
20
 
21
- def test_4(req)
21
+ def test4(req)
22
22
  Testdata::TestResponse.new(some_int: 4, full_response: req.to_json)
23
23
  end
24
24
  end
@@ -44,6 +44,7 @@ RSpec.describe MyServiceController, type: :request do
44
44
  }
45
45
 
46
46
  post '/test2?test_id=abc&foobar=xyz&timestamp_field=2024-04-03+01:02:03+UTC', params: params, as: :json
47
+ puts response.body
47
48
  expect(response).to be_successful
48
49
  expect(response.parsed_body).to eq({
49
50
  'someInt' => 2,
@@ -103,6 +104,20 @@ RSpec.describe MyServiceController, type: :request do
103
104
  }
104
105
  end
105
106
 
107
+ it 'should pass with incorrect field' do
108
+ params[:blarg] = 'himom'
109
+ post '/test4', params: params, as: :json
110
+ expect(response).to be_successful
111
+ end
112
+
113
+ it 'should fail in strict mode' do
114
+ GrpcRest.strict_mode = true
115
+ params[:blarg] = 'himom'
116
+ post '/test4', params: params, as: :json
117
+ expect(response).not_to be_successful
118
+ GrpcRest.strict_mode = false
119
+ end
120
+
106
121
  it 'should be successful' do
107
122
  post '/test4', params: params, as: :json
108
123
  expect(response).to be_successful
@@ -111,7 +126,7 @@ RSpec.describe MyServiceController, type: :request do
111
126
  expect(full_response).to eq(
112
127
  { 'testId' => 'abc',
113
128
  'foobar' => 'xyz',
114
- "mapField" => {"foo"=>{"anotherId"=>"id6", "subId"=>"id5"}},
129
+ 'mapField' => { 'foo' => { 'anotherId' => 'id6', 'subId' => 'id5' } },
115
130
  'repeatedString' => %w[W T F],
116
131
  'subRecord' => { 'subId' => 'id1', 'anotherId' => 'id2' },
117
132
  'secondRecord' => { 'subId' => 'id3', 'anotherId' => 'id4' },
@@ -141,7 +156,7 @@ RSpec.describe MyServiceController, type: :request do
141
156
  expect(full_response).to eq(
142
157
  { 'testId' => 'abc',
143
158
  'foobar' => 'xyz',
144
- "mapField" => {"foo"=>{"anotherId"=>"id6", "subId"=>"id5"}},
159
+ 'mapField' => { 'foo' => { 'anotherId' => 'id6', 'subId' => 'id5' } },
145
160
  'repeatedString' => %w[W T F],
146
161
  'subRecord' => { 'subId' => 'id1', 'anotherId' => 'id2' },
147
162
  'secondRecord' => { 'subId' => 'id3', 'anotherId' => 'id4' },
data/spec/gruf_spec.rb CHANGED
@@ -11,15 +11,15 @@ class GrufServerImpl < Gruf::Controllers::Base
11
11
  Testdata::TestResponse.new(some_int: 1, full_response: request.message.to_json)
12
12
  end
13
13
 
14
- def test_2
14
+ def test2
15
15
  Testdata::TestResponse.new(some_int: 2, full_response: request.message.to_json)
16
16
  end
17
17
 
18
- def test_3
18
+ def test3
19
19
  Testdata::TestResponse.new(some_int: 3, full_response: request.message.to_json)
20
20
  end
21
21
 
22
- def test_4
22
+ def test4
23
23
  Testdata::TestResponse.new(some_int: 4, full_response: request.message.to_json)
24
24
  end
25
25
 
@@ -1,65 +1,58 @@
1
- # frozen_string_literal: true
2
-
3
1
  ####### THIS FILE IS AUTOMATICALLY GENERATED BY protoc-gen-rails. DO NOT MODIFY. #######
4
2
 
5
3
  require 'grpc_rest'
6
4
  class MyServiceController < ActionController::Base
7
5
  protect_from_forgery with: :null_session
8
6
 
9
- rescue_from StandardError do |e|
10
- render json: GrpcRest.error_msg(e), status: :internal_server_error
11
- end
7
+ rescue_from StandardError do |e|
8
+ render json: GrpcRest.error_msg(e), status: :internal_server_error
9
+ end
12
10
  rescue_from GRPC::BadStatus do |e|
13
- render json: GrpcRest.error_msg(e), status: GrpcRest.grpc_http_status(e.code)
11
+ render json: GrpcRest.error_msg(e), status: GrpcRest.grpc_http_status(e.code)
14
12
  end
15
13
  rescue_from ActionDispatch::Http::Parameters::ParseError, Google::Protobuf::TypeError do |e|
16
14
  render json: GrpcRest.error_msg(e), status: :bad_request
17
15
  end
18
-
19
- METHOD_PARAM_MAP = {
20
-
21
- 'test' => [
22
- { name: 'foobar', val: 'blah/*', split_name: ['foobar'] }
23
- ],
24
-
25
- 'test_2' => [],
26
-
27
- 'test_3' => [
28
- { name: 'sub_record.sub_id', val: nil, split_name: %w[sub_record sub_id] }
29
- ],
30
-
31
- 'test_4' => []
32
- }.freeze
33
-
34
- def test
35
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
36
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
37
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
38
- GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP['test'], '', request.parameters)
39
- render json: GrpcRest.send_request('Testdata::MyService', 'test', grpc_request, { emit_defaults: true })
16
+ METHOD_PARAM_MAP = {"test"=>[{:name=>"foobar", :val=>"blah/*", :split_name=>["foobar"]}],
17
+ "test2"=>[],
18
+ "test3"=>
19
+ [{:name=>"sub_record.sub_id",
20
+ :val=>"",
21
+ :split_name=>["sub_record", "sub_id"]}],
22
+ "test4"=>[]}
23
+ .freeze
24
+
25
+
26
+ def test
27
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
28
+ except(*%w(controller action my_service))
29
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
30
+ GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test"], "", request.parameters)
31
+ render json: GrpcRest.send_request("Testdata::MyService", "test", grpc_request, {:emit_defaults=>true})
40
32
  end
41
33
 
42
- def test_2
43
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
44
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
45
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
46
- GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP['test_2'], 'second_record', request.parameters)
47
- render json: GrpcRest.send_request('Testdata::MyService', 'test_2', grpc_request, {})
34
+ def test2
35
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
36
+ except(*%w(controller action my_service))
37
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
38
+ GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test2"], "second_record", request.parameters)
39
+ render json: GrpcRest.send_request("Testdata::MyService", "test2", grpc_request, {})
48
40
  end
49
41
 
50
- def test_3
51
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
52
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
53
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
54
- GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP['test_3'], '', request.parameters)
55
- render json: GrpcRest.send_request('Testdata::MyService', 'test_3', grpc_request, {})
42
+ def test3
43
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
44
+ except(*%w(controller action my_service))
45
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
46
+ GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test3"], "", request.parameters)
47
+ render json: GrpcRest.send_request("Testdata::MyService", "test3", grpc_request, {})
56
48
  end
57
49
 
58
- def test_4
59
- fields = Testdata::TestRequest.descriptor.to_a.map(&:name)
60
- parameters = request.parameters.to_h.deep_transform_keys(&:underscore)
61
- grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters.slice(*fields))
62
- GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP['test_4'], '*', request.parameters)
63
- render json: GrpcRest.send_request('Testdata::MyService', 'test_4', grpc_request, {})
50
+ def test4
51
+ parameters = request.parameters.to_h.deep_transform_keys(&:underscore).
52
+ except(*%w(controller action my_service))
53
+ grpc_request = GrpcRest.init_request(Testdata::TestRequest, parameters)
54
+ GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["test4"], "*", request.parameters)
55
+ render json: GrpcRest.send_request("Testdata::MyService", "test4", grpc_request, {})
64
56
  end
57
+
65
58
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  ####### THIS FILE IS AUTOMATICALLY GENERATED BY protoc-gen-rails. DO NOT MODIFY. #######
4
4
 
5
- get '/test/*foobar' => 'my_service#test'
6
- post '/test2' => 'my_service#test_2'
7
- post '/test3/*sub_id' => 'my_service#test_3'
8
- post '/test4' => 'my_service#test_4'
5
+
6
+ get '/test/*foobar' => 'my_service#test'
7
+ post '/test2' => 'my_service#test2'
8
+ post '/test3/*sub_id' => 'my_service#test3'
9
+ post '/test4' => 'my_service#test4'
10
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Orner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-06 00:00:00.000000000 Z
11
+ date: 2025-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf