grpc-rest 0.1.22 → 0.1.25

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: 47964383a0aa5a5835edd72fae78e2febe1364fdd13f598a588dc3702f5f882b
4
- data.tar.gz: 14255db74de1d544d8964f3bb3b2e5515f6a25d50ab54bd0e00e6eb550ec9309
3
+ metadata.gz: 38281059f56037899cfff4869307d014ccbc2ec48556d5a8354367d166e06aec
4
+ data.tar.gz: 1f952b2758520d3e5d9763751cb61ec4ec5397f299a75f8513c08a1168f9d9e7
5
5
  SHA512:
6
- metadata.gz: 8d85e2f3169ec0dedff6f49e193ac1208caeee918c54b99ab3ee18f05973defad99edb8587fab5fe89cdbfb89d44278eda50f329e00e1bb304722ef10ef7c693
7
- data.tar.gz: 7ab65c78dc7aadac67a325705d28a3b79873ce24562fa02f1e4f71500536612d49c58806259ed8340b65bd53b3f2f64bf9946b597751d4ff67ae29b086856d63
6
+ metadata.gz: 88661401dcd71922e256ad80ec5767e41c6d346062ea87b5d55d2f27395f55c3e6a71cfd997f914ba9702f6f64f569049720bbd52814ffda5546237fae089f83
7
+ data.tar.gz: 9b9ab5e77e9c2dc8f7523ee1c2306607020adb4c10dd5728bd5116493351277fdf779fff2a83ba848bcfad35172afe8b67dbf76ea824fe524af5637b1c2e96aa
data/CHANGELOG CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ # 0.1.25 - 2025-04-30
11
+ - Fix for crash when parsing map fields
12
+
13
+ # 0.1.24 - 2024-12-09
14
+ - Log error backtraces.
15
+
16
+ # 0.1.23 - 2024-11-25
17
+ - Fix: Return a 400 status code when payload is invalid JSON
18
+
10
19
  # 0.1.22 - 2024-10-31
11
20
  - Fix: calling `fail!` in gruf Interceptors was failing with an unrelated exception.
12
21
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grpc-rest (0.1.21)
4
+ grpc-rest (0.1.25)
5
5
  grpc
6
6
  rails (>= 6.0)
7
7
 
@@ -1,3 +1,3 @@
1
1
  module GrpcRest
2
- VERSION = '0.1.22'
2
+ VERSION = '0.1.25'
3
3
  end
data/lib/grpc_rest.rb CHANGED
@@ -102,7 +102,10 @@ module GrpcRest
102
102
  next if val.nil?
103
103
 
104
104
  if descriptor.label == :repeated
105
- params[field] = val.map { |v| map_proto_type(descriptor, v) }
105
+ # leave map entries as key => value
106
+ unless descriptor.subtype&.options&.to_h&.dig(:map_entry)
107
+ params[field] = val.map { |v| map_proto_type(descriptor, v) }
108
+ end
106
109
  else
107
110
  params[field] = map_proto_type(descriptor, val)
108
111
  end
@@ -171,6 +174,7 @@ module GrpcRest
171
174
  end
172
175
 
173
176
  def error_msg(error)
177
+ Rails.logger.error("#{error.message}, backtrace: #{error.backtrace.join("\n")}")
174
178
  if error.respond_to?(:code)
175
179
  {
176
180
  code: error.code,
@@ -63,7 +63,7 @@ class {{.ControllerName}}Controller < ActionController::Base
63
63
  rescue_from GRPC::BadStatus do |e|
64
64
  render json: GrpcRest.error_msg(e), status: GrpcRest.grpc_http_status(e.code)
65
65
  end
66
- rescue_from Google::Protobuf::TypeError do |e|
66
+ rescue_from ActionDispatch::Http::Parameters::ParseError, Google::Protobuf::TypeError do |e|
67
67
  render json: GrpcRest.error_msg(e), status: :bad_request
68
68
  end
69
69
  METHOD_PARAM_MAP = {
@@ -102,20 +102,22 @@ func ProcessService(service *descriptorpb.ServiceDescriptorProto, pkg string) (F
102
102
  return FileResult{}, routes, err
103
103
  }
104
104
  restOpts, err := ExtractRestOptions(m)
105
- if err != nil { return FileResult{}, routes, err }
105
+ if err != nil {
106
+ return FileResult{}, routes, err
107
+ }
106
108
  httpMethod, path, err := MethodAndPath(opts.Pattern)
107
109
  pathInfo, err := ParsedPath(path)
108
110
  if err != nil {
109
111
  return FileResult{}, routes, err
110
112
  }
111
113
  controllerMethod := method{
112
- Name: strcase.ToSnake(m.GetName()),
113
- RequestType: Classify(m.GetInputType()),
114
- Path: path,
115
- RestOptions: rubyRestOptions(restOpts),
116
- HttpMethod: httpMethod,
117
- Body: opts.Body,
118
- PathInfo: pathInfo,
114
+ Name: strcase.ToSnake(m.GetName()),
115
+ RequestType: Classify(m.GetInputType()),
116
+ Path: path,
117
+ RestOptions: rubyRestOptions(restOpts),
118
+ HttpMethod: httpMethod,
119
+ Body: opts.Body,
120
+ PathInfo: pathInfo,
119
121
  }
120
122
  data.Methods = append(data.Methods, controllerMethod)
121
123
  routes = append(routes, Route{
@@ -11,9 +11,10 @@ class MyServiceController < ActionController::Base
11
11
  rescue_from GRPC::BadStatus do |e|
12
12
  render json: GrpcRest.error_msg(e), status: GrpcRest.grpc_http_status(e.code)
13
13
  end
14
- rescue_from Google::Protobuf::TypeError do |e|
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
+
17
18
  METHOD_PARAM_MAP = {
18
19
 
19
20
  "test" => [
@@ -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 {
@@ -71,6 +71,12 @@ RSpec.describe MyServiceController, type: :request do
71
71
  some_int: "65",
72
72
  foobar: 'xyz',
73
73
  repeated_string: ['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'
@@ -102,7 +108,7 @@ RSpec.describe MyServiceController, type: :request do
102
108
  expect(response).to be_successful
103
109
  expect(response.parsed_body).to eq({
104
110
  '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]})
111
+ '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],"mapField":{"foo":{"subId":"id5","anotherId":"id6"}}})
106
112
  })
107
113
  end
108
114
 
@@ -112,7 +118,7 @@ RSpec.describe MyServiceController, type: :request do
112
118
  expect(response).to be_successful
113
119
  expect(response.parsed_body).to eq({
114
120
  '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]})
121
+ '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],"mapField":{"foo":{"subId":"id5","anotherId":"id6"}}})
116
122
  })
117
123
  end
118
124
  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)
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.1.22
4
+ version: 0.1.25
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-10-31 00:00:00.000000000 Z
11
+ date: 2025-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc