action_controller-twirp 0.1.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22fa76662fce706d3efefc38981bfab8ed7cd01611e1d4de2bc8c7a8ad919e38
4
- data.tar.gz: 4479f03e25ef53f640feaaa9fb9e8c2e10e5202606f522da1949abbed88dfa5e
3
+ metadata.gz: ba5d8f3dbfc7dc8099def1e420b3a6c79cc2611df1295fad0c9e5f03ed3b1339
4
+ data.tar.gz: f2597df16242abd93b1ff1878b664db3f9e66cf63904e2030a47e000c32ba160
5
5
  SHA512:
6
- metadata.gz: b576978ee686292ac1150e876283101981094ce919e2d0c00bc202d7e5177badad3a9f29655aa3f7a6eed158e1ff02bbce89c8fb4998300cf4ba419f8a51729e
7
- data.tar.gz: b28a534f96ace98a8f2daad7bbe2e90f72cbce3533ad5133fadfa49aa0d4ab07006b649e79f0252e43be331868091255af951ae6934103a8659244684602dc4f
6
+ metadata.gz: ec99d0597b6d950cbf5f65c6900ef64ac855871520bb682d7f916a70aa1dcb6892152a190f487ab639098f4ba44757db9387a420ef22e603326ec08468964d3c
7
+ data.tar.gz: 780bf0fab5393d22940621111dfdf811c78007369c64b9a18cfa1f8e50b0adddf3300e07ef6a592605a936d987c481e73835e115109fccaa2a60e3b8ad6902d4
data/README.md CHANGED
@@ -51,13 +51,6 @@ Finally, implement rpc method your controller
51
51
  class UsersController < ApplicationController # :nodoc:
52
52
  include ActionController::Twirp
53
53
 
54
- rescue_from ActiveRecord::RecordNotFound do |e|
55
- twerr = Twirp::Error.not_found('The message',
56
- reason: e.class.name.demodulize,
57
- id: params[:id].to_s)
58
- render twirp_error: twerr
59
- end
60
-
61
54
  USERS = [
62
55
  { id: 1, name: 'Anna' },
63
56
  { id: 2, name: 'Reina' }
@@ -77,6 +70,48 @@ class UsersController < ApplicationController # :nodoc:
77
70
  end
78
71
  ```
79
72
 
73
+ ### Error handling
74
+
75
+ twirp-ruby eventually provides us with a rack app, which handles the exception and returns a response when an exception occurs.
76
+ Provide settings for exception handling, as the status code or body may be unexpected when an error occurs.
77
+
78
+ You can install initializer by rails generate command
79
+ ```sh
80
+ > bin/rails generate action_controller:twirp:install
81
+
82
+ > cat config/initializers/action_controller_twirp.rb
83
+ # frozen_string_literal: true
84
+
85
+ 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
+ # Mapping your exception classes and Twirp::Error::ERROR_CODES
96
+ # String => Symbol
97
+ # config.exception_codes = {
98
+ # 'ActiveRecord::RecordInvalid' => :invalid_argument,
99
+ # 'ActiveRecord::RecordNotFound' => :not_found,
100
+ # 'My::Exception' => :aborted,
101
+ # }
102
+
103
+ # Block to make Twirp::Error message when exception_codes exist
104
+ # config.build_message = ->(exception) {}
105
+
106
+ # Block to make Twirp::Error metadata. when exception_codes exist
107
+ # It MUST return Hash value
108
+ # config.build_metadata = ->(exception) {}
109
+
110
+ # Block to run additional process. e.g. logging
111
+ # config.on_exceptions = ->(exception) {}
112
+ end
113
+ ```
114
+
80
115
  ## Contributing
81
116
  Contribution directions go here.
82
117
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/module/attribute_accessors'
4
+
5
+ module ActionController
6
+ module Twirp
7
+ # Configration for ActionController::Twirp
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
+ # Mapping your exception classes and Twirp::Error::ERROR_CODES
19
+ mattr_accessor :exception_codes, default: {}
20
+
21
+ # Block to make Twirp::Error message
22
+ mattr_accessor :build_message, default: ->(exception) {}
23
+
24
+ # Block to make Twirp::Error metadata
25
+ mattr_accessor :build_metadata, default: ->(exception) {}
26
+
27
+ # Block to run additional process. e.g. logging
28
+ mattr_accessor :on_exceptions, default: ->(exception) {}
29
+
30
+ def self.setup
31
+ yield self
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,19 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'action_controller/twirp/twirp_error_renderer'
4
3
  require 'action_dispatch/twirp/railtie'
5
4
 
6
5
  module ActionController
7
6
  module Twirp
8
7
  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 = TwirpErrorRenderer.new(content, options)
13
- render(**renderer.to_render_option)
14
- end
15
- end
16
- end
17
8
  end
18
9
  end
19
10
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActionController
4
4
  module Twirp
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'action_controller/twirp/version'
4
4
  require 'action_controller/twirp/railtie'
5
+ require 'action_controller/twirp/config'
5
6
 
6
7
  module ActionController
7
8
  # Module to execute your implemented methods on Twirp with Rails
@@ -10,9 +11,9 @@ module ActionController
10
11
 
11
12
  # Override it to call a twirp class from request path
12
13
  def send_action(*_args)
13
- twirp_service_class.raise_exceptions = true
14
+ twirp_service_class.raise_exceptions = Config.handle_exceptions
14
15
 
15
- status, header, body = twirp_service_class.new(self)&.call(request.env)
16
+ status, header, body = twirp_action
16
17
 
17
18
  response.status = status
18
19
  response.header.merge!(header)
@@ -25,5 +26,35 @@ module ActionController
25
26
  class_name = request.path.split('/')[-2].underscore.gsub('.', '/').classify
26
27
  @twirp_service_class = "#{class_name}Service".constantize
27
28
  end
29
+
30
+ def twirp_action
31
+ twirp_service_class.new(self)&.call(request.env)
32
+ rescue StandardError => e
33
+ begin
34
+ Config.on_exceptions.call(e)
35
+ rescue StandardError => hook_e
36
+ e = hook_e
37
+ end
38
+ twirp_error_response(e)
39
+ end
40
+
41
+ def twirp_error_response(exception)
42
+ twerr = twirp_error(exception)
43
+ twirp_service_class.error_response(twerr)
44
+ 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
28
59
  end
29
60
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionController
4
+ module Twirp
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base # :nodoc:
7
+ source_root File.expand_path('../../templates', __dir__)
8
+
9
+ desc 'Creates a ActionController::Twirp initializer'
10
+ def copy_initializer
11
+ template 'action_controller_twirp.rb', 'config/initializers/action_controller_twirp.rb'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
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
+ # Mapping your exception classes and Twirp::Error::ERROR_CODES
14
+ # String => Symbol
15
+ # config.exception_codes = {
16
+ # 'ActiveRecord::RecordInvalid' => :invalid_argument,
17
+ # 'ActiveRecord::RecordNotFound' => :not_found,
18
+ # 'My::Exception' => :aborted,
19
+ # }
20
+
21
+ # Block to make Twirp::Error message when exception_codes exist
22
+ # config.build_message = ->(exception) {}
23
+
24
+ # Block to make Twirp::Error metadata. when exception_codes exist
25
+ # It MUST return Hash value
26
+ # config.build_metadata = ->(exception) {}
27
+
28
+ # Block to run additional process. e.g. logging
29
+ # config.on_exceptions = ->(exception) {}
30
+ end
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.1.1
4
+ version: 0.2.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-09-21 00:00:00.000000000 Z
11
+ date: 2022-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -63,11 +63,13 @@ files:
63
63
  - README.md
64
64
  - Rakefile
65
65
  - lib/action_controller/twirp.rb
66
+ - lib/action_controller/twirp/config.rb
66
67
  - lib/action_controller/twirp/railtie.rb
67
- - lib/action_controller/twirp/twirp_error_renderer.rb
68
68
  - lib/action_controller/twirp/version.rb
69
69
  - lib/action_dispatch/routing/mapper/twirp.rb
70
70
  - lib/action_dispatch/twirp/railtie.rb
71
+ - lib/generators/action_controller/twirp/install_generator.rb
72
+ - lib/generators/templates/action_controller_twirp.rb
71
73
  - lib/tasks/action_controller/twirp_tasks.rake
72
74
  homepage: https://github.com/arisawa/action_controller-twirp
73
75
  licenses:
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionController
4
- module Twirp
5
- # Convert Twirp::Error to #render option
6
- class TwirpErrorRenderer
7
- # @param content [Twirp::Error] 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?(::Twirp::Error)
11
- raise ArgumentError, 'Only Twirp::Error instance 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
- def twirp_error
28
- return @twirp_error if defined? @twirp_error
29
-
30
- code = @content.code
31
-
32
- @twirp_error = if ::Twirp::Error.valid_code?(code)
33
- @content
34
- else
35
- ::Twirp::Error.internal("Invalid code: #{code}", invalid_code: code.to_s)
36
- end
37
- end
38
-
39
- def status
40
- ::Twirp::ERROR_CODES_TO_HTTP_STATUS[twirp_error.code]
41
- end
42
-
43
- def content_type
44
- ::Twirp::Encoding::JSON
45
- end
46
- end
47
- end
48
- end