twirp 0.1.0 → 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.
- checksums.yaml +4 -4
- data/README.md +141 -62
- data/lib/twirp.rb +1 -0
- data/lib/twirp/client.rb +147 -0
- data/lib/twirp/error.rb +12 -8
- data/lib/twirp/service.rb +42 -76
- data/lib/twirp/service_dsl.rb +61 -0
- data/lib/twirp/version.rb +1 -1
- data/test/client_test.rb +203 -0
- data/test/fake_services.rb +21 -1
- data/test/service_test.rb +27 -28
- data/twirp.gemspec +6 -6
- metadata +30 -15
- data/.gitignore +0 -1
- data/Gemfile.lock +0 -20
- data/example/Gemfile +0 -7
- data/example/Gemfile.lock +0 -17
- data/example/gen/haberdasher_pb.rb +0 -18
- data/example/gen/haberdasher_twirp.rb +0 -10
- data/example/haberdasher.proto +0 -14
- data/example/main.rb +0 -14
- data/protoc-gen-twirp_ruby/main.go +0 -259
data/test/fake_services.rb
CHANGED
@@ -29,7 +29,11 @@ module Example
|
|
29
29
|
class Haberdasher < Twirp::Service
|
30
30
|
package "example"
|
31
31
|
service "Haberdasher"
|
32
|
-
rpc :MakeHat, Size, Hat, :
|
32
|
+
rpc :MakeHat, Size, Hat, :ruby_method => :make_hat
|
33
|
+
end
|
34
|
+
|
35
|
+
class HaberdasherClient < Twirp::Client
|
36
|
+
client_for Haberdasher
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
@@ -48,3 +52,19 @@ end
|
|
48
52
|
# Twirp Service with no package and no rpc methods.
|
49
53
|
class EmptyService < Twirp::Service
|
50
54
|
end
|
55
|
+
class EmptyClient < Twirp::Client
|
56
|
+
end
|
57
|
+
|
58
|
+
# Foo message
|
59
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
60
|
+
add_message "Foo" do
|
61
|
+
optional :foo, :string, 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
Foo = Google::Protobuf::DescriptorPool.generated_pool.lookup("Foo").msgclass
|
65
|
+
|
66
|
+
# Foo Client
|
67
|
+
class FooClient < Twirp::Client
|
68
|
+
service "Foo"
|
69
|
+
rpc :Foo, Foo, Foo, :ruby_method => :foo
|
70
|
+
end
|
data/test/service_test.rb
CHANGED
@@ -13,14 +13,14 @@ class ServiceTest < Minitest::Test
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# The rpc DSL should properly build the base Twirp environment for each rpc method.
|
16
|
-
def
|
17
|
-
assert_equal 1, Example::Haberdasher.
|
16
|
+
def test_rpcs_accessor
|
17
|
+
assert_equal 1, Example::Haberdasher.rpcs.size
|
18
18
|
assert_equal({
|
19
19
|
rpc_method: :MakeHat,
|
20
20
|
input_class: Example::Size,
|
21
21
|
output_class: Example::Hat,
|
22
|
-
|
23
|
-
}, Example::Haberdasher.
|
22
|
+
ruby_method: :make_hat,
|
23
|
+
}, Example::Haberdasher.rpcs["MakeHat"])
|
24
24
|
end
|
25
25
|
|
26
26
|
# DSL package and service define the proper data on the service
|
@@ -33,7 +33,7 @@ class ServiceTest < Minitest::Test
|
|
33
33
|
assert_equal "EmptyService", EmptyService.service_name # defaults to class name
|
34
34
|
assert_equal "EmptyService", EmptyService.service_full_name # with no package is just the service name
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def test_init_service
|
38
38
|
svc = Example::Haberdasher.new(HaberdasherHandler.new)
|
39
39
|
assert svc.respond_to?(:call) # so it is a Proc that can be used as Rack middleware
|
@@ -71,35 +71,35 @@ class ServiceTest < Minitest::Test
|
|
71
71
|
assert_equal 404, status
|
72
72
|
assert_equal 'application/json', headers['Content-Type']
|
73
73
|
assert_equal({
|
74
|
-
"code" => 'bad_route',
|
74
|
+
"code" => 'bad_route',
|
75
75
|
"msg" => 'Invalid rpc method "MakeUnicorns"',
|
76
76
|
"meta" => {"twirp_invalid_route" => "POST /twirp/example.Haberdasher/MakeUnicorns"},
|
77
|
-
}, JSON.parse(body[0]))
|
77
|
+
}, JSON.parse(body[0]))
|
78
78
|
end
|
79
79
|
|
80
80
|
def test_bad_route_with_wrong_http_method
|
81
|
-
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
81
|
+
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
82
82
|
method: "GET", input: '{"inches": 10}', "CONTENT_TYPE" => "application/json"
|
83
83
|
status, headers, body = haberdasher_service.call(rack_env)
|
84
84
|
|
85
85
|
assert_equal 404, status
|
86
86
|
assert_equal 'application/json', headers['Content-Type']
|
87
87
|
assert_equal({
|
88
|
-
"code" => 'bad_route',
|
88
|
+
"code" => 'bad_route',
|
89
89
|
"msg" => 'HTTP request method must be POST',
|
90
90
|
"meta" => {"twirp_invalid_route" => "GET /example.Haberdasher/MakeHat"},
|
91
91
|
}, JSON.parse(body[0]))
|
92
92
|
end
|
93
93
|
|
94
94
|
def test_bad_route_with_wrong_content_type
|
95
|
-
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
95
|
+
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
96
96
|
method: "POST", input: 'free text', "CONTENT_TYPE" => "text/plain"
|
97
97
|
status, headers, body = haberdasher_service.call(rack_env)
|
98
98
|
|
99
99
|
assert_equal 404, status
|
100
100
|
assert_equal 'application/json', headers['Content-Type']
|
101
101
|
assert_equal({
|
102
|
-
"code" => 'bad_route',
|
102
|
+
"code" => 'bad_route',
|
103
103
|
"msg" => 'unexpected Content-Type: "text/plain". Content-Type header must be one of application/json or application/protobuf',
|
104
104
|
"meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
|
105
105
|
}, JSON.parse(body[0]))
|
@@ -112,7 +112,7 @@ class ServiceTest < Minitest::Test
|
|
112
112
|
assert_equal 404, status
|
113
113
|
assert_equal 'application/json', headers['Content-Type']
|
114
114
|
assert_equal({
|
115
|
-
"code" => 'bad_route',
|
115
|
+
"code" => 'bad_route',
|
116
116
|
"msg" => 'Invalid route. Expected format: POST {BaseURL}/example.Haberdasher/{Method}',
|
117
117
|
"meta" => {"twirp_invalid_route" => "POST /wrongpath"},
|
118
118
|
}, JSON.parse(body[0]))
|
@@ -125,35 +125,35 @@ class ServiceTest < Minitest::Test
|
|
125
125
|
assert_equal 404, status
|
126
126
|
assert_equal 'application/json', headers['Content-Type'] # error responses are always JSON, even for Protobuf requests
|
127
127
|
assert_equal({
|
128
|
-
"code" => 'bad_route',
|
128
|
+
"code" => 'bad_route',
|
129
129
|
"msg" => 'Invalid route. Expected format: POST {BaseURL}/example.Haberdasher/{Method}',
|
130
130
|
"meta" => {"twirp_invalid_route" => "POST /another/wrong.Path/MakeHat"},
|
131
131
|
}, JSON.parse(body[0]))
|
132
132
|
end
|
133
133
|
|
134
134
|
def test_bad_route_with_wrong_json_body
|
135
|
-
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
135
|
+
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
136
136
|
method: "POST", input: 'bad json', "CONTENT_TYPE" => "application/json"
|
137
137
|
status, headers, body = haberdasher_service.call(rack_env)
|
138
138
|
|
139
139
|
assert_equal 404, status
|
140
140
|
assert_equal 'application/json', headers['Content-Type']
|
141
141
|
assert_equal({
|
142
|
-
"code" => 'bad_route',
|
142
|
+
"code" => 'bad_route',
|
143
143
|
"msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/json',
|
144
144
|
"meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
|
145
145
|
}, JSON.parse(body[0]))
|
146
146
|
end
|
147
147
|
|
148
148
|
def test_bad_route_with_wrong_protobuf_body
|
149
|
-
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
149
|
+
rack_env = Rack::MockRequest.env_for "example.Haberdasher/MakeHat",
|
150
150
|
method: "POST", input: 'bad protobuf', "CONTENT_TYPE" => "application/protobuf"
|
151
151
|
status, headers, body = haberdasher_service.call(rack_env)
|
152
152
|
|
153
153
|
assert_equal 404, status
|
154
154
|
assert_equal 'application/json', headers['Content-Type']
|
155
155
|
assert_equal({
|
156
|
-
"code" => 'bad_route',
|
156
|
+
"code" => 'bad_route',
|
157
157
|
"msg" => 'Invalid request body for rpc method "MakeHat" with Content-Type=application/protobuf',
|
158
158
|
"meta" => {"twirp_invalid_route" => "POST /example.Haberdasher/MakeHat"},
|
159
159
|
}, JSON.parse(body[0]))
|
@@ -230,7 +230,7 @@ class ServiceTest < Minitest::Test
|
|
230
230
|
assert_equal 400, status
|
231
231
|
assert_equal 'application/json', headers['Content-Type'] # error responses are always JSON, even for Protobuf requests
|
232
232
|
assert_equal({
|
233
|
-
"code" => 'invalid_argument',
|
233
|
+
"code" => 'invalid_argument',
|
234
234
|
"msg" => "I don't like that size",
|
235
235
|
}, JSON.parse(body[0]))
|
236
236
|
end
|
@@ -243,7 +243,7 @@ class ServiceTest < Minitest::Test
|
|
243
243
|
|
244
244
|
rack_env = proto_req "/example.Haberdasher/MakeHat", Example::Size.new
|
245
245
|
status, headers, body = svc.call(rack_env)
|
246
|
-
|
246
|
+
|
247
247
|
assert_equal 200, status
|
248
248
|
assert_equal "public, max-age=60", headers["Cache-Control"] # set by the handler
|
249
249
|
assert_equal "application/protobuf", headers["Content-Type"] # set by Twirp::Service
|
@@ -397,7 +397,7 @@ class ServiceTest < Minitest::Test
|
|
397
397
|
assert_equal 500, status
|
398
398
|
refute handler_called
|
399
399
|
assert_equal({
|
400
|
-
"code" => 'intenal',
|
400
|
+
"code" => 'intenal',
|
401
401
|
"msg" => 'error from before hook',
|
402
402
|
}, JSON.parse(body[0]))
|
403
403
|
end
|
@@ -474,7 +474,7 @@ class ServiceTest < Minitest::Test
|
|
474
474
|
assert_equal 500, status
|
475
475
|
assert_equal 'application/json', headers['Content-Type']
|
476
476
|
assert_equal({
|
477
|
-
"code" => 'intenal',
|
477
|
+
"code" => 'intenal',
|
478
478
|
"msg" => 'hook1 failed',
|
479
479
|
}, JSON.parse(body[0]))
|
480
480
|
|
@@ -517,7 +517,7 @@ class ServiceTest < Minitest::Test
|
|
517
517
|
assert_equal 500, status
|
518
518
|
refute success_called # after hook not called
|
519
519
|
assert_equal({
|
520
|
-
"code" => 'intenal',
|
520
|
+
"code" => 'intenal',
|
521
521
|
"msg" => 'error from handler',
|
522
522
|
}, JSON.parse(body[0]))
|
523
523
|
end
|
@@ -591,7 +591,7 @@ class ServiceTest < Minitest::Test
|
|
591
591
|
|
592
592
|
assert_equal 500, status
|
593
593
|
assert_equal({
|
594
|
-
"code" => 'intenal',
|
594
|
+
"code" => 'intenal',
|
595
595
|
"msg" => 'before failed',
|
596
596
|
}, JSON.parse(body[0]))
|
597
597
|
assert error_called
|
@@ -634,7 +634,7 @@ class ServiceTest < Minitest::Test
|
|
634
634
|
svc = Example::Haberdasher.new(HaberdasherHandler.new do |size, env|
|
635
635
|
return Twirp::Error.internal "handler error"
|
636
636
|
end)
|
637
|
-
|
637
|
+
|
638
638
|
error_called = false
|
639
639
|
svc.on_error do |twerr, env|
|
640
640
|
error_called = true
|
@@ -647,7 +647,7 @@ class ServiceTest < Minitest::Test
|
|
647
647
|
|
648
648
|
assert_equal 500, status
|
649
649
|
assert_equal({
|
650
|
-
"code" => 'intenal',
|
650
|
+
"code" => 'intenal',
|
651
651
|
"msg" => 'handler error',
|
652
652
|
}, JSON.parse(body[0]))
|
653
653
|
assert error_called
|
@@ -771,18 +771,17 @@ class ServiceTest < Minitest::Test
|
|
771
771
|
|
772
772
|
|
773
773
|
|
774
|
-
|
775
774
|
# Test Helpers
|
776
775
|
# ------------
|
777
776
|
|
778
777
|
def json_req(path, attrs)
|
779
|
-
Rack::MockRequest.env_for path, method: "POST",
|
778
|
+
Rack::MockRequest.env_for path, method: "POST",
|
780
779
|
input: JSON.generate(attrs),
|
781
780
|
"CONTENT_TYPE" => "application/json"
|
782
781
|
end
|
783
782
|
|
784
783
|
def proto_req(path, proto_message)
|
785
|
-
Rack::MockRequest.env_for path, method: "POST",
|
784
|
+
Rack::MockRequest.env_for path, method: "POST",
|
786
785
|
input: proto_message.class.encode(proto_message),
|
787
786
|
"CONTENT_TYPE" => "application/protobuf"
|
788
787
|
end
|
data/twirp.gemspec
CHANGED
@@ -10,16 +10,16 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ["Cyrus A. Forbes", "Mario Izquierdo"]
|
11
11
|
spec.email = ["forbescyrus@gmail.com", "tothemario@gmail.com"]
|
12
12
|
spec.summary = %q{Twirp services in Ruby.}
|
13
|
-
spec.description = %q{Twirp is a simple RPC framework with protobuf service definitions. The Twirp gem provides support for Ruby.}
|
13
|
+
spec.description = %q{Twirp is a simple RPC framework with protobuf service definitions. The Twirp gem provides native support for Ruby.}
|
14
14
|
spec.homepage = "https://github.com/cyrusaf/ruby-twirp"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files =
|
18
|
-
spec.
|
19
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.files = Dir['lib/**/*'] + %w(Gemfile LICENSE README.md twirp.gemspec)
|
18
|
+
spec.test_files = Dir['test/**/*']
|
20
19
|
spec.require_paths = ["lib"]
|
21
20
|
|
22
|
-
spec.add_runtime_dependency 'google-protobuf', '>= 3.0.0'
|
21
|
+
spec.add_runtime_dependency 'google-protobuf', '~> 3.0', '>= 3.0.0'
|
22
|
+
spec.add_runtime_dependency 'faraday', '~> 0'
|
23
23
|
|
24
|
-
spec.add_development_dependency 'bundler', '
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1'
|
25
25
|
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: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyrus A. Forbes
|
@@ -9,12 +9,15 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-04-07 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'
|
18
21
|
- - ">="
|
19
22
|
- !ruby/object:Gem::Version
|
20
23
|
version: 3.0.0
|
@@ -22,25 +25,42 @@ dependencies:
|
|
22
25
|
prerelease: false
|
23
26
|
version_requirements: !ruby/object:Gem::Requirement
|
24
27
|
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3.0'
|
25
31
|
- - ">="
|
26
32
|
- !ruby/object:Gem::Version
|
27
33
|
version: 3.0.0
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: faraday
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
type: :runtime
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
28
48
|
- !ruby/object:Gem::Dependency
|
29
49
|
name: bundler
|
30
50
|
requirement: !ruby/object:Gem::Requirement
|
31
51
|
requirements:
|
32
|
-
- - "
|
52
|
+
- - "~>"
|
33
53
|
- !ruby/object:Gem::Version
|
34
54
|
version: '1'
|
35
55
|
type: :development
|
36
56
|
prerelease: false
|
37
57
|
version_requirements: !ruby/object:Gem::Requirement
|
38
58
|
requirements:
|
39
|
-
- - "
|
59
|
+
- - "~>"
|
40
60
|
- !ruby/object:Gem::Version
|
41
61
|
version: '1'
|
42
62
|
description: Twirp is a simple RPC framework with protobuf service definitions. The
|
43
|
-
Twirp gem provides support for Ruby.
|
63
|
+
Twirp gem provides native support for Ruby.
|
44
64
|
email:
|
45
65
|
- forbescyrus@gmail.com
|
46
66
|
- tothemario@gmail.com
|
@@ -48,22 +68,16 @@ executables: []
|
|
48
68
|
extensions: []
|
49
69
|
extra_rdoc_files: []
|
50
70
|
files:
|
51
|
-
- ".gitignore"
|
52
71
|
- Gemfile
|
53
|
-
- Gemfile.lock
|
54
72
|
- LICENSE
|
55
73
|
- README.md
|
56
|
-
- example/Gemfile
|
57
|
-
- example/Gemfile.lock
|
58
|
-
- example/gen/haberdasher_pb.rb
|
59
|
-
- example/gen/haberdasher_twirp.rb
|
60
|
-
- example/haberdasher.proto
|
61
|
-
- example/main.rb
|
62
74
|
- lib/twirp.rb
|
75
|
+
- lib/twirp/client.rb
|
63
76
|
- lib/twirp/error.rb
|
64
77
|
- lib/twirp/service.rb
|
78
|
+
- lib/twirp/service_dsl.rb
|
65
79
|
- lib/twirp/version.rb
|
66
|
-
-
|
80
|
+
- test/client_test.rb
|
67
81
|
- test/error_test.rb
|
68
82
|
- test/fake_services.rb
|
69
83
|
- test/service_test.rb
|
@@ -88,11 +102,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
102
|
version: '0'
|
89
103
|
requirements: []
|
90
104
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.6.
|
105
|
+
rubygems_version: 2.6.8
|
92
106
|
signing_key:
|
93
107
|
specification_version: 4
|
94
108
|
summary: Twirp services in Ruby.
|
95
109
|
test_files:
|
110
|
+
- test/client_test.rb
|
96
111
|
- test/error_test.rb
|
97
112
|
- test/fake_services.rb
|
98
113
|
- test/service_test.rb
|
data/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
*.gem
|
data/Gemfile.lock
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
twirp (0.0.1)
|
5
|
-
google-protobuf (>= 3.0.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
google-protobuf (3.5.1.2)
|
11
|
-
|
12
|
-
PLATFORMS
|
13
|
-
ruby
|
14
|
-
|
15
|
-
DEPENDENCIES
|
16
|
-
bundler (>= 1)
|
17
|
-
twirp!
|
18
|
-
|
19
|
-
BUNDLED WITH
|
20
|
-
1.14.6
|
data/example/Gemfile
DELETED
data/example/Gemfile.lock
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
-
# source: haberdasher.proto
|
3
|
-
|
4
|
-
require 'google/protobuf'
|
5
|
-
|
6
|
-
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
-
add_message "example.HelloWorldRequest" do
|
8
|
-
optional :name, :string, 1
|
9
|
-
end
|
10
|
-
add_message "example.HelloWorldResponse" do
|
11
|
-
optional :message, :string, 1
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
module Example
|
16
|
-
HelloWorldRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("example.HelloWorldRequest").msgclass
|
17
|
-
HelloWorldResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("example.HelloWorldResponse").msgclass
|
18
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
# Code generated by protoc-gen-twirp_ruby, DO NOT EDIT.
|
2
|
-
require 'twirp'
|
3
|
-
|
4
|
-
module Example
|
5
|
-
class HaberdasherService < Twirp::Service
|
6
|
-
package "example"
|
7
|
-
service "Haberdasher"
|
8
|
-
rpc :HelloWorld, HelloWorldRequest, HelloWorldResponse, :handler_method => :hello_world
|
9
|
-
end
|
10
|
-
end
|