twirp 1.5.0 → 1.7.2
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 +4 -4
- data/lib/twirp/client_json.rb +3 -1
- data/lib/twirp/encoding.rb +8 -3
- data/lib/twirp/error.rb +1 -1
- data/lib/twirp/version.rb +1 -1
- data/test/client_json_test.rb +14 -0
- data/test/service_test.rb +47 -0
- data/twirp.gemspec +2 -2
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f17d89c29073da7ebffa780c9e8577e10f2537e28900344d8a055e098aa5f3d
|
4
|
+
data.tar.gz: 2932fb1abec1db6b14c3b39e8b7d2f81e318c0bdc02639d83a99bdfacd26001f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aca9edc089a15abfe4426880e8db8a8e2cac3f47ff056703e686dc14a3fe879a952a2b96c2de8bb06301b7406262601102c29fe48af6f9ead8775e9e2c76e35b
|
7
|
+
data.tar.gz: 10fc31c496e2fa4020ff9a643e08aa9ba333b0baa2324d1a42444ca6916d672a449eeef7ab22e674de81cc7a3e906d82fc97736714dfab29a999bfb4dd191f75
|
data/lib/twirp/client_json.rb
CHANGED
@@ -24,6 +24,7 @@ module Twirp
|
|
24
24
|
|
25
25
|
package = opts[:package].to_s
|
26
26
|
service = opts[:service].to_s
|
27
|
+
@strict = opts.fetch( :strict, false )
|
27
28
|
raise ArgumentError.new("Missing option :service") if service.empty?
|
28
29
|
@service_full_name = package.empty? ? service : "#{package}.#{service}"
|
29
30
|
end
|
@@ -33,7 +34,8 @@ module Twirp
|
|
33
34
|
def rpc(rpc_method, attrs={}, req_opts=nil)
|
34
35
|
body = Encoding.encode_json(attrs)
|
35
36
|
|
36
|
-
|
37
|
+
encoding = @strict ? Encoding::JSON_STRICT : Encoding::JSON
|
38
|
+
resp = self.class.make_http_request(@conn, @service_full_name, rpc_method, encoding, req_opts, body)
|
37
39
|
if resp.status != 200
|
38
40
|
return ClientResp.new(nil, self.class.error_from_response(resp))
|
39
41
|
end
|
data/lib/twirp/encoding.rb
CHANGED
@@ -17,13 +17,18 @@ module Twirp
|
|
17
17
|
|
18
18
|
module Encoding
|
19
19
|
JSON = "application/json"
|
20
|
+
# An opt-in content type useful when curling or manually testing a twirp
|
21
|
+
# service. This will fail if unknown fields are encountered. The return
|
22
|
+
# content type will be application/json.
|
23
|
+
JSON_STRICT = "application/json; strict=true"
|
20
24
|
PROTO = "application/protobuf"
|
21
25
|
|
22
26
|
class << self
|
23
27
|
|
24
28
|
def decode(bytes, msg_class, content_type)
|
25
29
|
case content_type
|
26
|
-
when JSON
|
30
|
+
when JSON then msg_class.decode_json(bytes, ignore_unknown_fields: true)
|
31
|
+
when JSON_STRICT then msg_class.decode_json(bytes, ignore_unknown_fields: false)
|
27
32
|
when PROTO then msg_class.decode(bytes)
|
28
33
|
else raise ArgumentError.new("Invalid content_type")
|
29
34
|
end
|
@@ -31,7 +36,7 @@ module Twirp
|
|
31
36
|
|
32
37
|
def encode(msg_obj, msg_class, content_type)
|
33
38
|
case content_type
|
34
|
-
when JSON
|
39
|
+
when JSON, JSON_STRICT then msg_class.encode_json(msg_obj, emit_defaults: true)
|
35
40
|
when PROTO then msg_class.encode(msg_obj)
|
36
41
|
else raise ArgumentError.new("Invalid content_type")
|
37
42
|
end
|
@@ -46,7 +51,7 @@ module Twirp
|
|
46
51
|
end
|
47
52
|
|
48
53
|
def valid_content_type?(content_type)
|
49
|
-
content_type == JSON || content_type == PROTO
|
54
|
+
content_type == JSON || content_type == PROTO || content_type == JSON_STRICT
|
50
55
|
end
|
51
56
|
|
52
57
|
def valid_content_types
|
data/lib/twirp/error.rb
CHANGED
@@ -25,7 +25,7 @@ module Twirp
|
|
25
25
|
already_exists: 409, # Conflict
|
26
26
|
permission_denied: 403, # Forbidden
|
27
27
|
unauthenticated: 401, # Unauthorized
|
28
|
-
resource_exhausted:
|
28
|
+
resource_exhausted: 429, # Too Many Requests
|
29
29
|
failed_precondition: 412, # Precondition Failed
|
30
30
|
aborted: 409, # Conflict
|
31
31
|
out_of_range: 400, # Bad Request
|
data/lib/twirp/version.rb
CHANGED
data/test/client_json_test.rb
CHANGED
@@ -29,6 +29,20 @@ class ClientJSONTest < Minitest::Test
|
|
29
29
|
assert_equal 3, resp.data["blah_resp"]
|
30
30
|
end
|
31
31
|
|
32
|
+
def test_client_json_strict_encoding
|
33
|
+
c = Twirp::ClientJSON.new(conn_stub("/my.pkg.Talking/Blah") {|req|
|
34
|
+
assert_equal "application/json; strict=true", req.request_headers['Content-Type']
|
35
|
+
assert_equal '{"blah1":1,"blah2":2}', req.body # body is json
|
36
|
+
|
37
|
+
[200, {}, '{"blah_resp": 3}']
|
38
|
+
}, package: "my.pkg", service: "Talking", strict: true)
|
39
|
+
|
40
|
+
resp = c.rpc :Blah, blah1: 1, blah2: 2
|
41
|
+
assert_nil resp.error
|
42
|
+
refute_nil resp.data
|
43
|
+
assert_equal 3, resp.data["blah_resp"]
|
44
|
+
end
|
45
|
+
|
32
46
|
def test_client_json_error
|
33
47
|
c = Twirp::ClientJSON.new(conn_stub("/Foo/Foomo") {|req|
|
34
48
|
[400, {}, '{"code": "invalid_argument", "msg": "dont like empty"}']
|
data/test/service_test.rb
CHANGED
@@ -64,6 +64,24 @@ class ServiceTest < Minitest::Test
|
|
64
64
|
assert_equal({"inches" => 10, "color" => "white"}, JSON.parse(body[0]))
|
65
65
|
end
|
66
66
|
|
67
|
+
def test_successful_json_strict_request_emit_defaults
|
68
|
+
rack_env = json_strict_req "/example.Haberdasher/MakeHat", inches: 0 # default int value
|
69
|
+
status, headers, body = haberdasher_service.call(rack_env)
|
70
|
+
|
71
|
+
assert_equal 200, status
|
72
|
+
assert_equal 'application/json; strict=true', headers['Content-Type']
|
73
|
+
assert_equal({"inches" => 0, "color" => "white"}, JSON.parse(body[0]))
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_successful_json_request_emit_defaults
|
77
|
+
rack_env = json_req "/example.Haberdasher/MakeHat", inches: 0 # default int value
|
78
|
+
status, headers, body = haberdasher_service.call(rack_env)
|
79
|
+
|
80
|
+
assert_equal 200, status
|
81
|
+
assert_equal 'application/json', headers['Content-Type']
|
82
|
+
assert_equal({"inches" => 0, "color" => "white"}, JSON.parse(body[0]))
|
83
|
+
end
|
84
|
+
|
67
85
|
def test_successful_proto_request
|
68
86
|
rack_env = proto_req "/example.Haberdasher/MakeHat", Example::Size.new(inches: 10)
|
69
87
|
status, headers, body = haberdasher_service.call(rack_env)
|
@@ -170,6 +188,29 @@ class ServiceTest < Minitest::Test
|
|
170
188
|
}, JSON.parse(body[0]))
|
171
189
|
end
|
172
190
|
|
191
|
+
def test_json_request_ignores_unknown_fields
|
192
|
+
rack_env = json_req "/example.Haberdasher/MakeHat", inches: 10, fake: 3
|
193
|
+
status, headers, body = haberdasher_service.call(rack_env)
|
194
|
+
|
195
|
+
assert_equal 200, status
|
196
|
+
assert_equal 'application/json', headers['Content-Type']
|
197
|
+
assert_equal({"inches" => 10, "color" => "white"}, JSON.parse(body[0]))
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_json_strict_request_fails_unknown_fields
|
201
|
+
rack_env = json_strict_req "/example.Haberdasher/MakeHat", inches: 10, fake: 3
|
202
|
+
status, headers, body = haberdasher_service.call(rack_env)
|
203
|
+
|
204
|
+
assert_equal 400, status
|
205
|
+
assert_equal 'application/json', headers['Content-Type']
|
206
|
+
assert_equal({
|
207
|
+
"code" => 'malformed',
|
208
|
+
"msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/json; strict=true: ' +
|
209
|
+
"Error occurred during parsing: No such field: fake",
|
210
|
+
"meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
|
211
|
+
}, JSON.parse(body[0]))
|
212
|
+
end
|
213
|
+
|
173
214
|
def test_bad_route_triggers_on_error_hooks
|
174
215
|
svc = haberdasher_service
|
175
216
|
|
@@ -791,6 +832,12 @@ class ServiceTest < Minitest::Test
|
|
791
832
|
"CONTENT_TYPE" => "application/json"
|
792
833
|
end
|
793
834
|
|
835
|
+
def json_strict_req(path, attrs)
|
836
|
+
Rack::MockRequest.env_for path, method: "POST",
|
837
|
+
input: JSON.generate(attrs),
|
838
|
+
"CONTENT_TYPE" => "application/json; strict=true"
|
839
|
+
end
|
840
|
+
|
794
841
|
def proto_req(path, proto_message)
|
795
842
|
Rack::MockRequest.env_for path, method: "POST",
|
796
843
|
input: proto_message.class.encode(proto_message),
|
data/twirp.gemspec
CHANGED
@@ -19,11 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.required_ruby_version = '>= 1.9'
|
22
|
-
spec.add_runtime_dependency 'google-protobuf', '~> 3.0', '>= 3.
|
22
|
+
spec.add_runtime_dependency 'google-protobuf', '~> 3.0', '>= 3.7.0'
|
23
23
|
spec.add_runtime_dependency 'faraday', '< 2' # for clients
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '~> 1'
|
26
26
|
spec.add_development_dependency 'minitest', '>= 5'
|
27
27
|
spec.add_development_dependency 'rake'
|
28
|
-
spec.add_development_dependency 'rack', '>= 2.
|
28
|
+
spec.add_development_dependency 'rack', '>= 2.2.3'
|
29
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twirp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyrus A. Forbes
|
@@ -9,28 +9,28 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-11-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: google-protobuf
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 3.0.0
|
21
18
|
- - "~>"
|
22
19
|
- !ruby/object:Gem::Version
|
23
20
|
version: '3.0'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 3.7.0
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
27
|
requirements:
|
28
|
-
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 3.0.0
|
31
28
|
- - "~>"
|
32
29
|
- !ruby/object:Gem::Version
|
33
30
|
version: '3.0'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.7.0
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: faraday
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,14 +93,14 @@ dependencies:
|
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 2.
|
96
|
+
version: 2.2.3
|
97
97
|
type: :development
|
98
98
|
prerelease: false
|
99
99
|
version_requirements: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 2.
|
103
|
+
version: 2.2.3
|
104
104
|
description: Twirp is a simple RPC framework with protobuf service definitions. The
|
105
105
|
Twirp gem provides native support for Ruby.
|
106
106
|
email:
|