grpc-rest 0.1.24 → 0.2.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/CI.yml +2 -41
  3. data/.rubocop.yml +3 -0
  4. data/CHANGELOG +6 -1
  5. data/Gemfile +3 -1
  6. data/Gemfile.lock +21 -10
  7. data/README.md +7 -8
  8. data/bin/protoc-gen-rails +6 -0
  9. data/grpc-rest.gemspec +4 -1
  10. data/lib/generator/controller.rb.erb +27 -0
  11. data/lib/generator/grpc.rb.erb +9 -0
  12. data/lib/generator/method.rb +96 -0
  13. data/lib/generator/output.rb +28 -0
  14. data/lib/generator/plugin_pb.rb +25 -0
  15. data/lib/generator/service.rb +36 -0
  16. data/lib/generator.rb +88 -0
  17. data/lib/grpc_rest/version.rb +3 -1
  18. data/lib/grpc_rest.rb +40 -38
  19. data/{protoc-gen-rails/testdata/base/app/controllers/my_service_controller.rb → spec/__snapshots__/service.snap} +33 -27
  20. data/spec/base_interceptor_spec.rb +6 -3
  21. data/spec/{protoc-gen-openapiv2 → gen/protoc-gen-openapiv2}/options/annotations_pb.rb +5 -4
  22. data/spec/{protoc-gen-openapiv2 → gen/protoc-gen-openapiv2}/options/openapiv2_pb.rb +30 -29
  23. data/spec/gen/test_pb.rb +15 -0
  24. data/spec/gen/test_service_pb.rb +23 -0
  25. data/spec/gen/test_service_services_pb.rb +26 -0
  26. data/spec/generator_spec.rb +49 -0
  27. data/spec/grpc_rest_spec.rb +71 -25
  28. data/spec/gruf_spec.rb +4 -3
  29. data/spec/spec_helper.rb +8 -6
  30. data/spec/test_service_pb.rb +1 -1
  31. data/spec/test_service_services_pb.rb +2 -1
  32. data/spec/testdata/base/app/controllers/my_service_controller.rb +65 -0
  33. data/spec/testdata/no_service/.keep +0 -0
  34. data/{protoc-gen-rails → spec}/testdata/test_service.proto +1 -0
  35. metadata +90 -26
  36. data/protoc-gen-rails/.goreleaser.yml +0 -27
  37. data/protoc-gen-rails/LICENSE +0 -21
  38. data/protoc-gen-rails/go.mod +0 -25
  39. data/protoc-gen-rails/go.sum +0 -49
  40. data/protoc-gen-rails/internal/output.go +0 -165
  41. data/protoc-gen-rails/internal/parse.go +0 -101
  42. data/protoc-gen-rails/internal/utils.go +0 -57
  43. data/protoc-gen-rails/main.go +0 -104
  44. data/protoc-gen-rails/main_test.go +0 -158
  45. /data/{protoc-gen-rails/testdata/no_service/.keep → spec/__snapshots__/no_service.snap} +0 -0
  46. /data/{protoc-gen-rails → spec}/google-deps/google/api/annotations.proto +0 -0
  47. /data/{protoc-gen-rails → spec}/google-deps/google/api/http.proto +0 -0
  48. /data/{protoc-gen-rails → spec}/google-deps/protoc-gen-openapiv2/options/annotations.proto +0 -0
  49. /data/{protoc-gen-rails → spec}/google-deps/protoc-gen-openapiv2/options/openapiv2.proto +0 -0
  50. /data/{protoc-gen-rails → spec}/testdata/base/config/routes/grpc.rb +0 -0
  51. /data/{protoc-gen-rails → spec}/testdata/test.proto +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # See https://github.com/rspec/rspec-rails/issues/1596#issuecomment-834282306
2
4
 
3
5
  require_relative './spec_helper'
@@ -22,24 +24,23 @@ class ServerImpl < Testdata::MyService::Service
22
24
  end
23
25
 
24
26
  RSpec.describe MyServiceController, type: :request do
25
-
26
27
  describe 'using get' do
27
28
  it 'should be successful' do
28
- get "/test/blah/xyz?test_id=abc"
29
+ get '/test/blah/xyz?test_id=abc'
29
30
  expect(response).to be_successful
30
31
  expect(response.parsed_body).to eq({
31
32
  'someInt' => 1,
32
33
  'fullResponse' => %({"testId":"abc","foobar":"xyz"}),
33
- "ignoredKey" => ''
34
+ 'ignoredKey' => ''
34
35
  })
35
36
  end
36
37
  end
37
38
 
38
39
  describe 'using body parameter' do
39
- it "should be successful" do
40
+ it 'should be successful' do
40
41
  params = {
41
- sub_id: "id1",
42
- another_id: "id2"
42
+ sub_id: 'id1',
43
+ another_id: 'id2'
43
44
  }
44
45
 
45
46
  post '/test2?test_id=abc&foobar=xyz&timestamp_field=2024-04-03+01:02:03+UTC', params: params, as: :json
@@ -49,7 +50,6 @@ RSpec.describe MyServiceController, type: :request do
49
50
  'fullResponse' => %({"testId":"abc","foobar":"xyz","secondRecord":{"subId":"id1","anotherId":"id2"},"timestampField":"2024-04-03T01:02:03Z"})
50
51
  })
51
52
  end
52
-
53
53
  end
54
54
 
55
55
  describe 'using sub-record splat' do
@@ -68,9 +68,15 @@ RSpec.describe MyServiceController, type: :request do
68
68
  {
69
69
  test_id: 'abc',
70
70
  repeated_float: [1.0, 2.0],
71
- some_int: "65",
71
+ some_int: '65',
72
72
  foobar: 'xyz',
73
- repeated_string: ['W', 'T', 'F'],
73
+ repeated_string: %w[W T F],
74
+ map_field: {
75
+ 'foo' => {
76
+ sub_id: 'id5',
77
+ another_id: 'id6'
78
+ }
79
+ },
74
80
  sub_record: {
75
81
  sub_id: 'id1',
76
82
  another_id: 'id2'
@@ -80,17 +86,17 @@ RSpec.describe MyServiceController, type: :request do
80
86
  another_id: 'id4'
81
87
  },
82
88
  struct_field: {
83
- "str_key": "val",
89
+ "str_key": 'val',
84
90
  "int_key": 123,
85
91
  "bool_key": true,
86
92
  "nil_key": nil,
87
93
  "list_key": [
88
- {
89
- "inner_key": "inner_val"
90
- }
91
- ]
94
+ {
95
+ "inner_key": 'inner_val'
96
+ }
97
+ ]
92
98
  },
93
- list_value: ['F', 'Y', 'I'],
99
+ list_value: %w[F Y I],
94
100
  bare_value: 45,
95
101
  timestamp_field: '2024-04-03 01:02:03 UTC',
96
102
  some_enum: 'TEST_ENUM_FOO'
@@ -100,29 +106,69 @@ RSpec.describe MyServiceController, type: :request do
100
106
  it 'should be successful' do
101
107
  post '/test4', params: params, as: :json
102
108
  expect(response).to be_successful
103
- expect(response.parsed_body).to eq({
104
- 'someInt' => 4,
105
- 'fullResponse' => %({"testId":"abc","foobar":"xyz","repeatedString":["W","T","F"],"subRecord":{"subId":"id1","anotherId":"id2"},"secondRecord":{"subId":"id3","anotherId":"id4"},"structField":{"bool_key":true,"str_key":"val","nil_key":null,"list_key":[{"inner_key":"inner_val"}],"int_key":123},"timestampField":"2024-04-03T01:02:03Z","listValue":["F","Y","I"],"bareValue":45,"someInt":65,"someEnum":"TEST_ENUM_FOO","repeatedFloat":[1,2]})
106
- })
109
+ json = response.parsed_body
110
+ full_response = JSON.parse(json['fullResponse'])
111
+ expect(full_response).to eq(
112
+ { 'testId' => 'abc',
113
+ 'foobar' => 'xyz',
114
+ "mapField" => {"foo"=>{"anotherId"=>"id6", "subId"=>"id5"}},
115
+ 'repeatedString' => %w[W T F],
116
+ 'subRecord' => { 'subId' => 'id1', 'anotherId' => 'id2' },
117
+ 'secondRecord' => { 'subId' => 'id3', 'anotherId' => 'id4' },
118
+ 'structField' => { 'bool_key' => true,
119
+ 'str_key' => 'val',
120
+ 'nil_key' => nil,
121
+ 'list_key' => [{ 'inner_key' => 'inner_val' }], 'int_key' => 123 },
122
+ 'timestampField' => '2024-04-03T01:02:03Z',
123
+ 'listValue' => %w[F Y I],
124
+ 'bareValue' => 45,
125
+ 'someInt' => 65,
126
+ 'someEnum' => 'TEST_ENUM_FOO',
127
+ 'repeatedFloat' => [1, 2] }
128
+ )
129
+ expect(response.parsed_body).to match({
130
+ 'someInt' => 4,
131
+ 'fullResponse' => a_kind_of(String)
132
+ })
107
133
  end
108
134
 
109
135
  it 'should be successful without the enum prefix' do
110
136
  params[:some_enum] = 'FOO'
111
137
  post '/test4', params: params, as: :json
112
138
  expect(response).to be_successful
113
- expect(response.parsed_body).to eq({
114
- 'someInt' => 4,
115
- 'fullResponse' => %({"testId":"abc","foobar":"xyz","repeatedString":["W","T","F"],"subRecord":{"subId":"id1","anotherId":"id2"},"secondRecord":{"subId":"id3","anotherId":"id4"},"structField":{"bool_key":true,"str_key":"val","nil_key":null,"list_key":[{"inner_key":"inner_val"}],"int_key":123},"timestampField":"2024-04-03T01:02:03Z","listValue":["F","Y","I"],"bareValue":45,"someInt":65,"someEnum":"TEST_ENUM_FOO","repeatedFloat":[1,2]})
116
- })
139
+ json = response.parsed_body
140
+ full_response = JSON.parse(json['fullResponse'])
141
+ expect(full_response).to eq(
142
+ { 'testId' => 'abc',
143
+ 'foobar' => 'xyz',
144
+ "mapField" => {"foo"=>{"anotherId"=>"id6", "subId"=>"id5"}},
145
+ 'repeatedString' => %w[W T F],
146
+ 'subRecord' => { 'subId' => 'id1', 'anotherId' => 'id2' },
147
+ 'secondRecord' => { 'subId' => 'id3', 'anotherId' => 'id4' },
148
+ 'structField' => { 'bool_key' => true,
149
+ 'str_key' => 'val',
150
+ 'nil_key' => nil,
151
+ 'list_key' => [{ 'inner_key' => 'inner_val' }], 'int_key' => 123 },
152
+ 'timestampField' => '2024-04-03T01:02:03Z',
153
+ 'listValue' => %w[F Y I],
154
+ 'bareValue' => 45,
155
+ 'someInt' => 65,
156
+ 'someEnum' => 'TEST_ENUM_FOO',
157
+ 'repeatedFloat' => [1, 2] }
158
+ )
159
+ expect(response.parsed_body).to match({
160
+ 'someInt' => 4,
161
+ 'fullResponse' => a_kind_of(String)
162
+ })
117
163
  end
118
164
  end
119
165
 
120
166
  describe 'numeric timestamp' do
121
167
  it 'should be successful' do
122
168
  params = {
123
- timestamp_field: 1712692452
169
+ timestamp_field: 1_712_692_452
124
170
  }
125
- post "/test4", params: params, as: :json
171
+ post '/test4', params: params, as: :json
126
172
  expect(response).to be_successful
127
173
  expect(response.parsed_body).to eq({
128
174
  'someInt' => 4,
data/spec/gruf_spec.rb CHANGED
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './spec_helper'
2
4
  require_relative './test_service_services_pb'
3
5
  require 'gruf'
4
6
 
5
7
  class GrufServerImpl < Gruf::Controllers::Base
6
-
7
8
  bind ::Testdata::MyService::Service
8
9
 
9
10
  def test
@@ -38,12 +39,12 @@ RSpec.describe MyServiceController, type: :request do
38
39
  describe 'using get' do
39
40
  it 'should be successful and call interceptors' do
40
41
  GrufServerImpl.intercepted = false
41
- get "/test/blah/xyz?test_id=abc"
42
+ get '/test/blah/xyz?test_id=abc'
42
43
  expect(response).to be_successful
43
44
  expect(response.parsed_body).to eq({
44
45
  'someInt' => 1,
45
46
  'fullResponse' => %({"testId":"abc","foobar":"xyz"}),
46
- "ignoredKey" => ''
47
+ 'ignoredKey' => ''
47
48
  })
48
49
  expect(GrufServerImpl.intercepted).to eq(true)
49
50
  end
data/spec/spec_helper.rb CHANGED
@@ -1,26 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_controller/railtie"
3
+ require 'action_controller/railtie'
4
4
 
5
5
  class GrpcApp < Rails::Application
6
6
  initializer(:host_config) do
7
- Rails.application.config.hosts << "www.example.com"
7
+ Rails.application.config.hosts << 'www.example.com'
8
8
  end
9
9
  end
10
10
  GrpcApp.initialize!
11
11
 
12
12
  require 'rspec/rails'
13
+ require 'rspec/snapshot'
13
14
 
14
15
  loader = Zeitwerk::Loader.new
15
16
  loader.push_dir('./spec')
16
17
  loader.inflector.inflect('protoc-gen-openapiv2' => 'ProtocGenOpenapiv2')
17
18
  loader.ignore("#{Rails.root}/spec/test_service_pb.rb")
18
19
  loader.setup
20
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
21
+ $LOAD_PATH.unshift(File.expand_path('gen', __dir__))
22
+
19
23
  require "#{Rails.root}/spec/test_service_pb.rb"
20
24
  require "#{Rails.root}/lib/base_interceptor.rb"
21
25
 
22
- $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
23
-
24
26
  RSpec.configure do |config|
25
27
  config.full_backtrace = true
26
28
  config.render_views
@@ -31,8 +33,8 @@ RSpec.configure do |config|
31
33
  end
32
34
  end
33
35
 
34
- require_relative '../protoc-gen-rails/testdata/base/app/controllers/my_service_controller'
35
- Rails.application.routes.draw_paths.push("#{Rails.root}/protoc-gen-rails/testdata/base/config/routes")
36
+ require_relative 'testdata/base/app/controllers/my_service_controller'
37
+ Rails.application.routes.draw_paths.push("#{Rails.root}/spec/testdata/base/config/routes")
36
38
  Rails.application.routes.draw do
37
39
  draw(:grpc)
38
40
  end
@@ -10,7 +10,7 @@ require 'google/protobuf/timestamp_pb'
10
10
  require 'protoc-gen-openapiv2/options/annotations_pb'
11
11
 
12
12
 
13
- descriptor_data = "\n\x12test_service.proto\x12\x08testdata\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\xd7\x03\n\x0bTestRequest\x12\x0f\n\x07test_id\x18\x01 \x01(\t\x12\x0e\n\x06\x66oobar\x18\x02 \x01(\t\x12\x17\n\x0frepeated_string\x18\x03 \x03(\t\x12\'\n\nsub_record\x18\x04 \x01(\x0b\x32\x13.testdata.SubRecord\x12*\n\rsecond_record\x18\x05 \x01(\x0b\x32\x13.testdata.SubRecord\x12-\n\x0cstruct_field\x18\x06 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x33\n\x0ftimestamp_field\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nlist_value\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.ListValue\x12*\n\nbare_value\x18\t \x01(\x0b\x32\x16.google.protobuf.Value\x12(\n\x0bsub_records\x18\n \x03(\x0b\x32\x13.testdata.SubRecord\x12\x10\n\x08some_int\x18\x0b \x01(\x05\x12%\n\tsome_enum\x18\x0c \x01(\x0e\x32\x12.testdata.TestEnum\x12\x16\n\x0erepeated_float\x18\r \x03(\x02\"/\n\tSubRecord\x12\x0e\n\x06sub_id\x18\x01 \x01(\t\x12\x12\n\nanother_id\x18\x02 \x01(\t\"L\n\x0cTestResponse\x12\x10\n\x08some_int\x18\x01 \x01(\x05\x12\x15\n\rfull_response\x18\x02 \x01(\t\x12\x13\n\x0bignored_key\x18\x03 \x01(\t*K\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x32\x83\x03\n\tMyService\x12x\n\x04Test\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"A\x92\x41!j\x1f\n\x19x-grpc-rest-emit-defaults\x12\x02 \x01\x82\xd3\xe4\x93\x02\x17\x12\x15/test/{foobar=blah/*}\x12U\n\x05Test2\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x1d\x82\xd3\xe4\x93\x02\x17\"\x06/test2:\rsecond_record\x12Z\n\x05Test3\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x1a/test3/{sub_record.sub_id}\x12I\n\x05Test4\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x11\x82\xd3\xe4\x93\x02\x0b\"\x06/test4:\x01*b\x06proto3"
13
+ descriptor_data = "\n\x12test_service.proto\x12\x08testdata\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\xd5\x04\n\x0bTestRequest\x12\x0f\n\x07test_id\x18\x01 \x01(\t\x12\x0e\n\x06\x66oobar\x18\x02 \x01(\t\x12\x17\n\x0frepeated_string\x18\x03 \x03(\t\x12\'\n\nsub_record\x18\x04 \x01(\x0b\x32\x13.testdata.SubRecord\x12*\n\rsecond_record\x18\x05 \x01(\x0b\x32\x13.testdata.SubRecord\x12-\n\x0cstruct_field\x18\x06 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x33\n\x0ftimestamp_field\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nlist_value\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.ListValue\x12*\n\nbare_value\x18\t \x01(\x0b\x32\x16.google.protobuf.Value\x12(\n\x0bsub_records\x18\n \x03(\x0b\x32\x13.testdata.SubRecord\x12\x10\n\x08some_int\x18\x0b \x01(\x05\x12%\n\tsome_enum\x18\x0c \x01(\x0e\x32\x12.testdata.TestEnum\x12\x16\n\x0erepeated_float\x18\r \x03(\x02\x12\x36\n\tmap_field\x18\x0e \x03(\x0b\x32#.testdata.TestRequest.MapFieldEntry\x1a\x44\n\rMapFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\"\n\x05value\x18\x02 \x01(\x0b\x32\x13.testdata.SubRecord:\x02\x38\x01\"/\n\tSubRecord\x12\x0e\n\x06sub_id\x18\x01 \x01(\t\x12\x12\n\nanother_id\x18\x02 \x01(\t\"L\n\x0cTestResponse\x12\x10\n\x08some_int\x18\x01 \x01(\x05\x12\x15\n\rfull_response\x18\x02 \x01(\t\x12\x13\n\x0bignored_key\x18\x03 \x01(\t*K\n\x08TestEnum\x12\x19\n\x15TEST_ENUM_UNSPECIFIED\x10\x00\x12\x11\n\rTEST_ENUM_FOO\x10\x01\x12\x11\n\rTEST_ENUM_BAR\x10\x02\x32\x83\x03\n\tMyService\x12x\n\x04Test\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"A\x92\x41!j\x1f\n\x19x-grpc-rest-emit-defaults\x12\x02 \x01\x82\xd3\xe4\x93\x02\x17\x12\x15/test/{foobar=blah/*}\x12U\n\x05Test2\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x1d\x82\xd3\xe4\x93\x02\x17\"\x06/test2:\rsecond_record\x12Z\n\x05Test3\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\"\x82\xd3\xe4\x93\x02\x1c\"\x1a/test3/{sub_record.sub_id}\x12I\n\x05Test4\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x11\x82\xd3\xe4\x93\x02\x0b\"\x06/test4:\x01*b\x06proto3"
14
14
 
15
15
  pool = Google::Protobuf::DescriptorPool.generated_pool
16
16
  pool.add_serialized_file(descriptor_data)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Generated by the protocol buffer compiler. DO NOT EDIT!
2
4
  # Source: test_service.proto for package 'testdata'
3
5
 
@@ -7,7 +9,6 @@ require 'test_service_pb'
7
9
  module Testdata
8
10
  module MyService
9
11
  class Service
10
-
11
12
  include ::GRPC::GenericService
12
13
 
13
14
  self.marshal_class_method = :encode
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ ####### THIS FILE IS AUTOMATICALLY GENERATED BY protoc-gen-rails. DO NOT MODIFY. #######
4
+
5
+ require 'grpc_rest'
6
+ class MyServiceController < ActionController::Base
7
+ protect_from_forgery with: :null_session
8
+
9
+ rescue_from StandardError do |e|
10
+ render json: GrpcRest.error_msg(e), status: :internal_server_error
11
+ end
12
+ rescue_from GRPC::BadStatus do |e|
13
+ render json: GrpcRest.error_msg(e), status: GrpcRest.grpc_http_status(e.code)
14
+ end
15
+ rescue_from ActionDispatch::Http::Parameters::ParseError, Google::Protobuf::TypeError do |e|
16
+ render json: GrpcRest.error_msg(e), status: :bad_request
17
+ 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 })
40
+ end
41
+
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, {})
48
+ end
49
+
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, {})
56
+ end
57
+
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, {})
64
+ end
65
+ end
File without changes
@@ -21,6 +21,7 @@ message TestRequest {
21
21
  int32 some_int = 11;
22
22
  TestEnum some_enum = 12;
23
23
  repeated float repeated_float = 13;
24
+ map<string, SubRecord> map_field = 14;
24
25
  }
25
26
 
26
27
  message SubRecord {
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.24
4
+ version: 0.2.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: 2024-12-09 00:00:00.000000000 Z
11
+ date: 2025-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: google-protobuf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.30.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.30.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: grpc
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +53,7 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: '6.0'
41
55
  - !ruby/object:Gem::Dependency
42
- name: rspec-rails
56
+ name: byebug
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
@@ -66,50 +80,85 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-snapshot
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  description:
70
112
  email:
71
113
  - daniel.orner@flipp.com
72
- executables: []
114
+ executables:
115
+ - protoc-gen-rails
73
116
  extensions: []
74
117
  extra_rdoc_files: []
75
118
  files:
76
119
  - ".github/workflows/CI.yml"
77
120
  - ".gitignore"
121
+ - ".rubocop.yml"
78
122
  - CHANGELOG
79
123
  - CODE_OF_CONDUCT.md
80
124
  - Gemfile
81
125
  - Gemfile.lock
82
126
  - README.md
127
+ - bin/protoc-gen-rails
83
128
  - grpc-rest.gemspec
84
129
  - lib/base_interceptor.rb
130
+ - lib/generator.rb
131
+ - lib/generator/controller.rb.erb
132
+ - lib/generator/grpc.rb.erb
133
+ - lib/generator/method.rb
134
+ - lib/generator/output.rb
135
+ - lib/generator/plugin_pb.rb
136
+ - lib/generator/service.rb
85
137
  - lib/grpc_rest.rb
86
138
  - lib/grpc_rest/version.rb
87
- - protoc-gen-rails/.goreleaser.yml
88
- - protoc-gen-rails/LICENSE
89
- - protoc-gen-rails/go.mod
90
- - protoc-gen-rails/go.sum
91
- - protoc-gen-rails/google-deps/google/api/annotations.proto
92
- - protoc-gen-rails/google-deps/google/api/http.proto
93
- - protoc-gen-rails/google-deps/protoc-gen-openapiv2/options/annotations.proto
94
- - protoc-gen-rails/google-deps/protoc-gen-openapiv2/options/openapiv2.proto
95
- - protoc-gen-rails/internal/output.go
96
- - protoc-gen-rails/internal/parse.go
97
- - protoc-gen-rails/internal/utils.go
98
- - protoc-gen-rails/main.go
99
- - protoc-gen-rails/main_test.go
100
- - protoc-gen-rails/testdata/base/app/controllers/my_service_controller.rb
101
- - protoc-gen-rails/testdata/base/config/routes/grpc.rb
102
- - protoc-gen-rails/testdata/no_service/.keep
103
- - protoc-gen-rails/testdata/test.proto
104
- - protoc-gen-rails/testdata/test_service.proto
139
+ - spec/__snapshots__/no_service.snap
140
+ - spec/__snapshots__/service.snap
105
141
  - spec/base_interceptor_spec.rb
142
+ - spec/gen/protoc-gen-openapiv2/options/annotations_pb.rb
143
+ - spec/gen/protoc-gen-openapiv2/options/openapiv2_pb.rb
144
+ - spec/gen/test_pb.rb
145
+ - spec/gen/test_service_pb.rb
146
+ - spec/gen/test_service_services_pb.rb
147
+ - spec/generator_spec.rb
148
+ - spec/google-deps/google/api/annotations.proto
149
+ - spec/google-deps/google/api/http.proto
150
+ - spec/google-deps/protoc-gen-openapiv2/options/annotations.proto
151
+ - spec/google-deps/protoc-gen-openapiv2/options/openapiv2.proto
106
152
  - spec/grpc_rest_spec.rb
107
153
  - spec/gruf_spec.rb
108
- - spec/protoc-gen-openapiv2/options/annotations_pb.rb
109
- - spec/protoc-gen-openapiv2/options/openapiv2_pb.rb
110
154
  - spec/spec_helper.rb
111
155
  - spec/test_service_pb.rb
112
156
  - spec/test_service_services_pb.rb
157
+ - spec/testdata/base/app/controllers/my_service_controller.rb
158
+ - spec/testdata/base/config/routes/grpc.rb
159
+ - spec/testdata/no_service/.keep
160
+ - spec/testdata/test.proto
161
+ - spec/testdata/test_service.proto
113
162
  homepage: ''
114
163
  licenses:
115
164
  - MIT
@@ -134,11 +183,26 @@ signing_key:
134
183
  specification_version: 4
135
184
  summary: Generate Rails controllers and routes from gRPC definitions.
136
185
  test_files:
186
+ - spec/__snapshots__/no_service.snap
187
+ - spec/__snapshots__/service.snap
137
188
  - spec/base_interceptor_spec.rb
189
+ - spec/gen/protoc-gen-openapiv2/options/annotations_pb.rb
190
+ - spec/gen/protoc-gen-openapiv2/options/openapiv2_pb.rb
191
+ - spec/gen/test_pb.rb
192
+ - spec/gen/test_service_pb.rb
193
+ - spec/gen/test_service_services_pb.rb
194
+ - spec/generator_spec.rb
195
+ - spec/google-deps/google/api/annotations.proto
196
+ - spec/google-deps/google/api/http.proto
197
+ - spec/google-deps/protoc-gen-openapiv2/options/annotations.proto
198
+ - spec/google-deps/protoc-gen-openapiv2/options/openapiv2.proto
138
199
  - spec/grpc_rest_spec.rb
139
200
  - spec/gruf_spec.rb
140
- - spec/protoc-gen-openapiv2/options/annotations_pb.rb
141
- - spec/protoc-gen-openapiv2/options/openapiv2_pb.rb
142
201
  - spec/spec_helper.rb
143
202
  - spec/test_service_pb.rb
144
203
  - spec/test_service_services_pb.rb
204
+ - spec/testdata/base/app/controllers/my_service_controller.rb
205
+ - spec/testdata/base/config/routes/grpc.rb
206
+ - spec/testdata/no_service/.keep
207
+ - spec/testdata/test.proto
208
+ - spec/testdata/test_service.proto
@@ -1,27 +0,0 @@
1
- project_name: protoc-gen-rails
2
- before:
3
- hooks:
4
- - go mod tidy
5
- builds:
6
- - env:
7
- - CGO_ENABLED=0
8
- dir: .
9
- goos:
10
- - linux
11
- - darwin
12
- binary: protoc-gen-rails
13
- changelog:
14
- sort: asc
15
- filters:
16
- exclude:
17
- - '^docs:'
18
- - '^test:'
19
-
20
- release:
21
- github:
22
- owner: flipp-oss
23
- name: grpc-rest
24
-
25
- archives:
26
- - id: protoc-gen-rails
27
- name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Flipp
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,25 +0,0 @@
1
- module github.com/flipp-oss/protoc-gen-rails
2
-
3
- go 1.22.0
4
-
5
- require (
6
- github.com/iancoleman/strcase v0.3.0
7
- github.com/stretchr/testify v1.8.4
8
- google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280
9
- google.golang.org/protobuf v1.34.2
10
- )
11
-
12
- require (
13
- github.com/davecgh/go-spew v1.1.1 // indirect
14
- github.com/google/go-cmp v0.6.0 // indirect
15
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
16
- github.com/kr/pretty v0.3.1 // indirect
17
- github.com/pmezard/go-difflib v1.0.0 // indirect
18
- github.com/rogpeppe/go-internal v1.12.0 // indirect
19
- golang.org/x/text v0.17.0 // indirect
20
- google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect
21
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 // indirect
22
- google.golang.org/grpc v1.65.0 // indirect
23
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
24
- gopkg.in/yaml.v3 v3.0.1 // indirect
25
- )
@@ -1,49 +0,0 @@
1
- github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
2
- github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3
- github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4
- github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
5
- github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
6
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
7
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
8
- github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
9
- github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
10
- github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
11
- github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
12
- github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
13
- github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
14
- github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
15
- github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
16
- github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
17
- github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
18
- github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
19
- github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
20
- github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
21
- github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
22
- github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
23
- github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
24
- github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
25
- golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
26
- golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
27
- google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg=
28
- google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
29
- google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8=
30
- google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
31
- google.golang.org/genproto/googleapis/api v0.0.0-20240228224816-df926f6c8641 h1:SO1wX9btGFrwj9EzH3ocqfwiPVOxfv4ggAJajzlHA5s=
32
- google.golang.org/genproto/googleapis/api v0.0.0-20240228224816-df926f6c8641/go.mod h1:wLupoVsUfYPgOMwjzhYFbaVklw/INms+dqTp0tc1fv8=
33
- google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
34
- google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
35
- google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280 h1:YDFM9oOjiFhaMAVgbDxfxW+66nRrsvzQzJ51wp3OxC0=
36
- google.golang.org/genproto/googleapis/api v0.0.0-20240820151423-278611b39280/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
37
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280 h1:XQMA2e105XNlEZ8NRF0HqnUOZzP14sUSsgL09kpdNnU=
38
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240820151423-278611b39280/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
39
- google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
40
- google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
41
- google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
42
- google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
43
- google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
44
- google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
45
- gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
46
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
47
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
48
- gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
49
- gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=