grpc-rest 0.1.16 → 0.1.18

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: 461dd3e8eb1185e6b30d1bfe5c62e07cf63f09d8c9d6beb3cc50d16c9a637933
4
- data.tar.gz: d8f6683a57212a7485f06648365d76192c8910a63a7b9938ab816dd6df251944
3
+ metadata.gz: 8c776db1bb156562864c41be6a4af47debe30d420329359847e71db6b5913711
4
+ data.tar.gz: 7c4745a5d2dd7e560d0e18b022972473a4487bedf9b9efc4ba387d5cbe42bfc0
5
5
  SHA512:
6
- metadata.gz: e37a3b27b16712f40b18207442eed3dcf176446c30951e692aedb027716f6b784dd046917a5db532e7fd313998fddcbeed41efafbbdc399a570c0fb7c380ae39
7
- data.tar.gz: ccfa637e8573b108cdff2c713a71aa532aa074484696e53a678b37905b74f3d037b38eae22b6d1d7582c1e4faa46f9cc72330fffb496ca1d0b22bd0b7d245aae
6
+ metadata.gz: 4e7f53b6c264c80f768dd91c0c25da350651cd386d7a51b88f7eedf814d2f0eced41a261ee9e3800ba867fdb69bc4a87ac22700c6b33ae3d50d576555b66875e
7
+ data.tar.gz: 456d38962848fc73f1c40f0a59336de1d17017e2e138511f046836674a947a11390b20b7180a4b7d4d5befa6f132a23793d5cc7518263a93c1ed0be8255fa246
data/CHANGELOG CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## UNRELEASED
9
9
 
10
+ # 0.1.18 - 2024-08-15
11
+ - Automatically add prefixes to enum values if not provided
12
+
13
+ # 0.1.17 - 2024-07-30
14
+ - Ignore unknown fields in JSON decoding
15
+
10
16
  # 0.1.16 - 2024-07-09
11
17
  - Support requests in camel case
12
18
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grpc-rest (0.1.15)
4
+ grpc-rest (0.1.17)
5
5
  grpc
6
6
  rails (>= 6.0)
7
7
 
@@ -1,3 +1,3 @@
1
1
  module GrpcRest
2
- VERSION = '0.1.16'
2
+ VERSION = '0.1.18'
3
3
  end
data/lib/grpc_rest.rb CHANGED
@@ -37,12 +37,45 @@ module GrpcRest
37
37
  proto.public_send(:"#{tokens.last}=", value) if proto.respond_to?(:"#{tokens.last}=")
38
38
  end
39
39
 
40
+ # https://stackoverflow.com/a/2158473/5199431
41
+ def longest_common_substring(arr)
42
+ return "" if arr.empty?
43
+
44
+ result = 0
45
+ first_val = arr[0]
46
+ (0...first_val.length).each do |k|
47
+ all_matched = true
48
+ character = first_val[k]
49
+ arr.each { |str| all_matched &= (character == str[k]) }
50
+ break unless all_matched
51
+ result += 1
52
+ end
53
+ first_val.slice(0, result)
54
+ end
55
+
56
+ def handle_enum_values(descriptor, value)
57
+ names = descriptor.subtype.to_h.keys.map(&:to_s)
58
+ prefix = longest_common_substring(names)
59
+ if prefix.present? && !value.starts_with?(prefix)
60
+ "#{prefix}#{value}"
61
+ else
62
+ value
63
+ end
64
+ end
65
+
40
66
  def map_proto_type(proto, params)
41
67
  proto.to_a.each do |descriptor|
42
68
  field = descriptor.name
43
69
  val = params[field]
44
70
  next if val.nil?
45
- next if descriptor.subtype.is_a?(Google::Protobuf::EnumDescriptor)
71
+ if descriptor.subtype.is_a?(Google::Protobuf::EnumDescriptor)
72
+ if descriptor.label == :repeated
73
+ params[field] = val.map { |v| handle_enum_values(descriptor, v)}
74
+ else
75
+ params[field] = handle_enum_values(descriptor, val)
76
+ end
77
+ next
78
+ end
46
79
 
47
80
  case descriptor.type
48
81
  when *%i(int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64)
@@ -80,7 +113,7 @@ module GrpcRest
80
113
 
81
114
  def init_request(request_class, params)
82
115
  map_proto_type(request_class.descriptor, params)
83
- request_class.decode_json(JSON.generate(params))
116
+ request_class.decode_json(JSON.generate(params), ignore_unknown_fields: true)
84
117
  end
85
118
 
86
119
  def assign_params(request, param_hash, body_string, params)
@@ -18,6 +18,7 @@ message TestRequest {
18
18
  google.protobuf.Value bare_value = 9;
19
19
  repeated SubRecord sub_records = 10;
20
20
  int32 some_int = 11;
21
+ TestEnum some_enum = 12;
21
22
  }
22
23
 
23
24
  message SubRecord {
@@ -30,6 +31,12 @@ message TestResponse {
30
31
  string full_response = 2;
31
32
  }
32
33
 
34
+ enum TestEnum {
35
+ TEST_ENUM_UNSPECIFIED = 0;
36
+ TEST_ENUM_FOO = 1;
37
+ TEST_ENUM_BAR = 2;
38
+ }
39
+
33
40
  service MyService {
34
41
  rpc Test(TestRequest) returns (TestResponse) {
35
42
  option (google.api.http) = {
@@ -63,8 +63,8 @@ RSpec.describe MyServiceController, type: :request do
63
63
  end
64
64
 
65
65
  describe 'full body splat' do
66
- it 'should be successful' do
67
- params = {
66
+ let(:params) do
67
+ {
68
68
  test_id: 'abc',
69
69
  some_int: "65",
70
70
  foobar: 'xyz',
@@ -91,12 +91,26 @@ RSpec.describe MyServiceController, type: :request do
91
91
  list_value: ['F', 'Y', 'I'],
92
92
  bare_value: 45,
93
93
  timestamp_field: '2024-04-03 01:02:03 UTC',
94
+ some_enum: 'TEST_ENUM_FOO'
94
95
  }
96
+ end
97
+
98
+ it 'should be successful' do
99
+ post '/test4', params: params, as: :json
100
+ expect(response).to be_successful
101
+ expect(response.parsed_body).to eq({
102
+ 'someInt' => 4,
103
+ '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"})
104
+ })
105
+ end
106
+
107
+ it 'should be successful without the enum prefix' do
108
+ params[:some_enum] = 'FOO'
95
109
  post '/test4', params: params, as: :json
96
110
  expect(response).to be_successful
97
111
  expect(response.parsed_body).to eq({
98
112
  'someInt' => 4,
99
- '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})
113
+ '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"})
100
114
  })
101
115
  end
102
116
  end
@@ -9,7 +9,7 @@ require 'google/protobuf/struct_pb'
9
9
  require 'google/protobuf/timestamp_pb'
10
10
 
11
11
 
12
- descriptor_data = "\n\x12test_service.proto\x12\x08testdata\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x98\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\"/\n\tSubRecord\x12\x0e\n\x06sub_id\x18\x01 \x01(\t\x12\x12\n\nanother_id\x18\x02 \x01(\t\"7\n\x0cTestResponse\x12\x10\n\x08some_int\x18\x01 \x01(\x05\x12\x15\n\rfull_response\x18\x02 \x01(\t2\xdf\x02\n\tMyService\x12T\n\x04Test\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x1d\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"
12
+ descriptor_data = "\n\x12test_service.proto\x12\x08testdata\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xbf\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\"/\n\tSubRecord\x12\x0e\n\x06sub_id\x18\x01 \x01(\t\x12\x12\n\nanother_id\x18\x02 \x01(\t\"7\n\x0cTestResponse\x12\x10\n\x08some_int\x18\x01 \x01(\x05\x12\x15\n\rfull_response\x18\x02 \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\xdf\x02\n\tMyService\x12T\n\x04Test\x12\x15.testdata.TestRequest\x1a\x16.testdata.TestResponse\"\x1d\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
13
 
14
14
  pool = Google::Protobuf::DescriptorPool.generated_pool
15
15
  pool.add_serialized_file(descriptor_data)
@@ -18,4 +18,5 @@ module Testdata
18
18
  TestRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("testdata.TestRequest").msgclass
19
19
  SubRecord = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("testdata.SubRecord").msgclass
20
20
  TestResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("testdata.TestResponse").msgclass
21
+ TestEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("testdata.TestEnum").enummodule
21
22
  end
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.16
4
+ version: 0.1.18
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-07-09 00:00:00.000000000 Z
11
+ date: 2024-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grpc