action_controller-twirp 0.2.0 → 0.3.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 +68 -23
- data/lib/action_controller/twirp/config.rb +0 -9
- data/lib/action_controller/twirp/error.rb +41 -0
- data/lib/action_controller/twirp/error_renderer.rb +42 -0
- data/lib/action_controller/twirp/railtie.rb +9 -0
- data/lib/action_controller/twirp/version.rb +1 -1
- data/lib/action_controller/twirp.rb +3 -16
- data/lib/generators/templates/action_controller_twirp.rb +0 -9
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17541f1f7bae98a4beb49d20368f0bcbb60b5c0284e6763ead869f13bc333784
|
4
|
+
data.tar.gz: 272ddd872c4a7176abcba1b78baf20478e37f93338bc5002ef4537f21e4d8289
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b8ea6ac39900c875734119e47552d0425bb18e49e8ca878d30901e38ff5293cf2f59729220bef4184670dc80086d951cf055cfbdfdaa0d5f42d562139acde74
|
7
|
+
data.tar.gz: 3314d20c05db3d93fd07d75b840baec2b60f3d5a581e3e11e76df1da87d15e520a015cd4dbd426a6c3b5e3eba5f89da5c5ddffbd6a6ce4e6787c3cde740822ea
|
data/README.md
CHANGED
@@ -29,7 +29,12 @@ It provides routing method `twirp` that maps twirp service class and Rails contr
|
|
29
29
|
|
30
30
|
First, you should generate twirp service class. see: [example in twirp-ruby](https://github.com/twitchtv/twirp-ruby/wiki#usage-example)
|
31
31
|
|
32
|
-
Next,
|
32
|
+
Next, install initializer.
|
33
|
+
```sh
|
34
|
+
bin/rails g action_controller:twirp:install
|
35
|
+
```
|
36
|
+
|
37
|
+
Next, add twirp action in config/routes.rb.
|
33
38
|
```ruby
|
34
39
|
Rails.application.routes.draw do
|
35
40
|
scope :twirp do
|
@@ -38,7 +43,7 @@ Rails.application.routes.draw do
|
|
38
43
|
end
|
39
44
|
```
|
40
45
|
|
41
|
-
Result of `bin/rails routes
|
46
|
+
Result of `bin/rails routes`.
|
42
47
|
```sh
|
43
48
|
> bin/rails routes
|
44
49
|
Prefix Verb URI Pattern Controller#Action
|
@@ -46,9 +51,9 @@ Result of `bin/rails routes`
|
|
46
51
|
POST /twirp/example.v1.UserApi/GetUser(.:format) users#get_user
|
47
52
|
```
|
48
53
|
|
49
|
-
Finally, implement rpc method your controller
|
54
|
+
Finally, implement rpc method your controller.
|
50
55
|
```ruby
|
51
|
-
class UsersController < ApplicationController
|
56
|
+
class UsersController < ApplicationController
|
52
57
|
include ActionController::Twirp
|
53
58
|
|
54
59
|
USERS = [
|
@@ -72,33 +77,47 @@ end
|
|
72
77
|
|
73
78
|
### Error handling
|
74
79
|
|
75
|
-
|
76
|
-
Provide settings for exception handling, as the status code or body may be unexpected when an error occurs.
|
80
|
+
We must follow protocol when using Twirp. Specifically,
|
77
81
|
|
78
|
-
|
79
|
-
|
80
|
-
|
82
|
+
- It accepts request parameters specified in proto file, and must return response body.
|
83
|
+
- If an exception occurs, a response body of Twirp::Error's JSON must be returned.
|
84
|
+
|
85
|
+
This section describes when an exception occurs.
|
86
|
+
|
87
|
+
The following blocks are in the order of method calls when requested to the Rails app. (It's quite simplified)
|
88
|
+
```
|
89
|
+
:
|
90
|
+
ActionController::Metal#dispatch
|
91
|
+
AbstractController::Base#process
|
92
|
+
:
|
93
|
+
ActionController::Rescue#process_action
|
94
|
+
ActionController::Callbacks#process_action
|
95
|
+
:
|
96
|
+
(Some module's #process_action is called)
|
97
|
+
:
|
98
|
+
AbstractController::Base#process_action
|
99
|
+
AbstractController::Base#send_action
|
100
|
+
```
|
101
|
+
|
102
|
+
The gem is only override `#send_action`. It follows twirp protocal in this one.
|
103
|
+
|
104
|
+
For example, if an exception occurs in the callback, Rails app will return a response, so we must be implemented so that the twirp protocol can be followed.
|
105
|
+
|
106
|
+
This is easy to do, see below.
|
81
107
|
|
108
|
+
First, modify `exception_codes` config.
|
109
|
+
```sh
|
82
110
|
> cat config/initializers/action_controller_twirp.rb
|
83
111
|
# frozen_string_literal: true
|
84
112
|
|
85
113
|
ActionController::Twirp::Config.setup do |config|
|
86
|
-
# Handle exceptions
|
87
|
-
# true: handling by ActionController::Twirp
|
88
|
-
# false: handling by Twirp::Service (default)
|
89
|
-
# config.handle_exceptions = false
|
90
|
-
|
91
|
-
# ---
|
92
|
-
# The following configurations ignore when handle_exceptions is false
|
93
|
-
# ---
|
94
|
-
|
95
114
|
# Mapping your exception classes and Twirp::Error::ERROR_CODES
|
96
115
|
# String => Symbol
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
116
|
+
config.exception_codes = {
|
117
|
+
'ActiveRecord::RecordInvalid' => :invalid_argument,
|
118
|
+
'ActiveRecord::RecordNotFound' => :not_found,
|
119
|
+
'MyApp::Unauthenticated' => :unauthenticated,
|
120
|
+
}
|
102
121
|
|
103
122
|
# Block to make Twirp::Error message when exception_codes exist
|
104
123
|
# config.build_message = ->(exception) {}
|
@@ -112,6 +131,32 @@ ActionController::Twirp::Config.setup do |config|
|
|
112
131
|
end
|
113
132
|
```
|
114
133
|
|
134
|
+
Next, write a `rescue_from` block as usual and use the `:twirp_error` key on `#render`
|
135
|
+
```ruby
|
136
|
+
class UsersController < ApplicationController
|
137
|
+
include ActionController::Twirp
|
138
|
+
|
139
|
+
before_action :authenticate!
|
140
|
+
|
141
|
+
rescue_from MyApp::Unauthenticated do |e|
|
142
|
+
render twirp_error: e
|
143
|
+
end
|
144
|
+
|
145
|
+
:
|
146
|
+
:
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def authenticate!
|
151
|
+
return if your_logic
|
152
|
+
|
153
|
+
raise MyApp::Unauthenticated
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
See [dummy app controller](test/dummy/app/controllers/users_controller.rb) and [integration test](test/integration/users_test.rb) for details.
|
159
|
+
|
115
160
|
## Contributing
|
116
161
|
Contribution directions go here.
|
117
162
|
|
@@ -6,15 +6,6 @@ module ActionController
|
|
6
6
|
module Twirp
|
7
7
|
# Configration for ActionController::Twirp
|
8
8
|
module Config
|
9
|
-
# Handle exceptions
|
10
|
-
# true: handling by ActionController::Twirp
|
11
|
-
# false: handling by Twirp::Service
|
12
|
-
mattr_accessor :handle_exceptions, default: false
|
13
|
-
|
14
|
-
# ---
|
15
|
-
# The following configurations ignore when handle_exceptions is false
|
16
|
-
# ---
|
17
|
-
|
18
9
|
# Mapping your exception classes and Twirp::Error::ERROR_CODES
|
19
10
|
mattr_accessor :exception_codes, default: {}
|
20
11
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'action_controller/twirp/config'
|
4
|
+
|
5
|
+
module ActionController
|
6
|
+
module Twirp
|
7
|
+
# Class to generate Twirp::Error from an exception class and Config
|
8
|
+
class Error
|
9
|
+
# @param content [Exception] given as a value of :twirp_error key of render method.
|
10
|
+
def initialize(exception)
|
11
|
+
unless exception.is_a?(Exception)
|
12
|
+
raise ArgumentError, 'Instance of Exception class can be specified'
|
13
|
+
end
|
14
|
+
|
15
|
+
@exception = exception
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate
|
19
|
+
if Config.exception_codes.key?(exception_name)
|
20
|
+
code = Config.exception_codes[exception_name]
|
21
|
+
message = Config.build_message.call(exception)
|
22
|
+
metadata = Config.build_metadata.call(exception)
|
23
|
+
|
24
|
+
::Twirp::Error.public_send(code, message, metadata)
|
25
|
+
else
|
26
|
+
::Twirp::Error.internal_with(exception)
|
27
|
+
end
|
28
|
+
rescue StandardError => e
|
29
|
+
::Twirp::Error.internal_with(e)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :exception
|
35
|
+
|
36
|
+
def exception_name
|
37
|
+
exception.class.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Twirp
|
5
|
+
# Convert Twirp::Error to #render option
|
6
|
+
class ErrorRenderer
|
7
|
+
# @param content [Exception] given as a value of :twirp_error key of render method.
|
8
|
+
# @param options [Hash] options of render method.
|
9
|
+
def initialize(content, options)
|
10
|
+
unless content.is_a?(Exception)
|
11
|
+
raise ArgumentError, 'Instance of Exception class can be specified'
|
12
|
+
end
|
13
|
+
|
14
|
+
@content = content
|
15
|
+
@options = options.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_render_option
|
19
|
+
{
|
20
|
+
json: twirp_error.to_h,
|
21
|
+
**@options.merge(status: status, content_type: content_type)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :content, :options
|
28
|
+
|
29
|
+
def twirp_error
|
30
|
+
@twirp_error ||= Error.new(content).generate
|
31
|
+
end
|
32
|
+
|
33
|
+
def status
|
34
|
+
::Twirp::ERROR_CODES_TO_HTTP_STATUS[twirp_error.code]
|
35
|
+
end
|
36
|
+
|
37
|
+
def content_type
|
38
|
+
::Twirp::Encoding::JSON
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,10 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'action_controller/twirp/error_renderer'
|
3
4
|
require 'action_dispatch/twirp/railtie'
|
4
5
|
|
5
6
|
module ActionController
|
6
7
|
module Twirp
|
7
8
|
class Railtie < ::Rails::Railtie # :nodoc:
|
9
|
+
initializer 'action_controller.twirp' do
|
10
|
+
ActiveSupport.on_load(:action_controller) do
|
11
|
+
ActionController::Renderers.add :twirp_error do |content, options|
|
12
|
+
renderer = ErrorRenderer.new(content, options)
|
13
|
+
render(**renderer.to_render_option)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
8
17
|
end
|
9
18
|
end
|
10
19
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'action_controller/twirp/version'
|
4
4
|
require 'action_controller/twirp/railtie'
|
5
5
|
require 'action_controller/twirp/config'
|
6
|
+
require 'action_controller/twirp/error'
|
6
7
|
|
7
8
|
module ActionController
|
8
9
|
# Module to execute your implemented methods on Twirp with Rails
|
@@ -11,7 +12,7 @@ module ActionController
|
|
11
12
|
|
12
13
|
# Override it to call a twirp class from request path
|
13
14
|
def send_action(*_args)
|
14
|
-
twirp_service_class.raise_exceptions =
|
15
|
+
twirp_service_class.raise_exceptions = true
|
15
16
|
|
16
17
|
status, header, body = twirp_action
|
17
18
|
|
@@ -39,22 +40,8 @@ module ActionController
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def twirp_error_response(exception)
|
42
|
-
twerr =
|
43
|
+
twerr = Error.new(exception).generate
|
43
44
|
twirp_service_class.error_response(twerr)
|
44
45
|
end
|
45
|
-
|
46
|
-
def twirp_error(exception)
|
47
|
-
if Config.exception_codes.key?(exception.class.to_s)
|
48
|
-
code = Config.exception_codes[exception.class.to_s]
|
49
|
-
message = Config.build_message.call(exception)
|
50
|
-
metadata = Config.build_metadata.call(exception)
|
51
|
-
|
52
|
-
::Twirp::Error.public_send(code, message, metadata)
|
53
|
-
else
|
54
|
-
::Twirp::Error.internal_with(exception)
|
55
|
-
end
|
56
|
-
rescue StandardError => e
|
57
|
-
::Twirp::Error.internal_with(e)
|
58
|
-
end
|
59
46
|
end
|
60
47
|
end
|
@@ -1,15 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
ActionController::Twirp::Config.setup do |config|
|
4
|
-
# Handle exceptions
|
5
|
-
# true: handling by ActionTwirpRails
|
6
|
-
# false: handling by Twirp::Service (default)
|
7
|
-
# config.handle_exceptions = false
|
8
|
-
|
9
|
-
# ---
|
10
|
-
# The following configurations ignore when handle_exceptions is false
|
11
|
-
# ---
|
12
|
-
|
13
4
|
# Mapping your exception classes and Twirp::Error::ERROR_CODES
|
14
5
|
# String => Symbol
|
15
6
|
# config.exception_codes = {
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_controller-twirp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kosuke Arisawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -64,6 +64,8 @@ files:
|
|
64
64
|
- Rakefile
|
65
65
|
- lib/action_controller/twirp.rb
|
66
66
|
- lib/action_controller/twirp/config.rb
|
67
|
+
- lib/action_controller/twirp/error.rb
|
68
|
+
- lib/action_controller/twirp/error_renderer.rb
|
67
69
|
- lib/action_controller/twirp/railtie.rb
|
68
70
|
- lib/action_controller/twirp/version.rb
|
69
71
|
- lib/action_dispatch/routing/mapper/twirp.rb
|