twirp 1.5.0 → 1.7.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|