action_controller-twirp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f6de4da76df23f5785f040d5e30c5b7c6f9a641f70c913a6bce1861cb9d8001d
4
+ data.tar.gz: 7ac05c58f7c1bbf94a3f24625ba04e3e7e74511124a83bd2dab8a23448356dfc
5
+ SHA512:
6
+ metadata.gz: 02f89f5b0c538f22d79c457bfd1e86f9948a085236165406ecc0793fc54b697284112adb6912ee274fffc04e24355e432675c3f9923f8536611d0ec1dbe66174
7
+ data.tar.gz: 432b4da795794b2decd181836e9a5752bea31db4b94bb361e7a049c2fbaac40b048eb0186885900aeb5f13e514785a8dc87ddcea6f2e3dac6fc664bf69c19997
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Kosuke Arisawa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # ActionController::Twirp
2
+
3
+ [![build](https://github.com/arisawa/action_controller-twirp/actions/workflows/ruby.yml/badge.svg)](https://github.com/arisawa/action_controller-twirp/actions/workflows/ruby.yml)
4
+ ![License](https://img.shields.io/github/license/arisawa/action_controller-twirp)
5
+
6
+ Implement twirp service with Rails controller.
7
+
8
+ ## Installation
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "action_controller-twirp"
13
+ ```
14
+
15
+ And then execute:
16
+ ```bash
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+ ```bash
22
+ $ gem install action_controller-twirp
23
+ ```
24
+
25
+ ## Usage
26
+ [twirp-ruby](https://github.com/twitchtv/twirp-ruby) with Ruby on Rails.
27
+
28
+ It provides routing method `twirp` that maps twirp service class and Rails controller class, and a module of `ActionController::Twirp` to help execute RPC methods and rendering Twirp::Error.
29
+
30
+ First, you should generate twirp service class. see: [example in twirp-ruby](https://github.com/twitchtv/twirp-ruby/wiki#usage-example)
31
+
32
+ Next, add twirp action in config/routes.rb
33
+ ```ruby
34
+ Rails.application.routes.draw do
35
+ scope :twirp do
36
+ twirp Example::V1::UserApiService, controller: 'users'
37
+ end
38
+ end
39
+ ```
40
+
41
+ Result of `bin/rails routes`
42
+ ```sh
43
+ > bin/rails routes
44
+ Prefix Verb URI Pattern Controller#Action
45
+ POST /twirp/example.v1.UserApi/ListUsers(.:format) users#list_users
46
+ POST /twirp/example.v1.UserApi/GetUser(.:format) users#get_user
47
+ ```
48
+
49
+ Finally, implement rpc method your controller
50
+ ```ruby
51
+ class UsersController < ApplicationController # :nodoc:
52
+ include ActionController::Twirp
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
+ USERS = [
62
+ { id: 1, name: 'Anna' },
63
+ { id: 2, name: 'Reina' }
64
+ ].freeze
65
+
66
+ def list_users(_req, _env)
67
+ Example::V1::ListUsersResponse.new(users: USERS)
68
+ end
69
+
70
+ def get_user(req, _env)
71
+ user = USERS.find { |u| u[:id] == req.id }
72
+
73
+ raise ActiveRecord::RecordNotFound unless user
74
+
75
+ Example::V1::User.new(user)
76
+ end
77
+ end
78
+ ```
79
+
80
+ ## Contributing
81
+ Contribution directions go here.
82
+
83
+ ## License
84
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'bundler/gem_tasks'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_controller/twirp/twirp_error_renderer'
4
+ require 'action_dispatch/twirp/railtie'
5
+
6
+ module ActionController
7
+ module Twirp
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 = TwirpErrorRenderer.new(content, options)
13
+ render(**renderer.to_render_option)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionController
4
+ module Twirp
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_controller/twirp/version'
4
+ require 'action_controller/twirp/railtie'
5
+
6
+ module ActionController
7
+ # Module to execute your implemented methods on Twirp with Rails
8
+ module Twirp
9
+ private
10
+
11
+ # Override it to call a twirp class from request path
12
+ def send_action(*_args)
13
+ twirp_service_class.raise_exceptions = true
14
+
15
+ status, header, body = twirp_service_class.new(self)&.call(request.env)
16
+
17
+ response.status = status
18
+ response.header.merge(header)
19
+ response.body = body
20
+ end
21
+
22
+ def twirp_service_class
23
+ return @twirp_service_class if defined? @twirp_service_class
24
+
25
+ class_name = request.path.split('/')[-2].underscore.gsub('.', '/').classify
26
+ @twirp_service_class = "#{class_name}Service".constantize
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Routing
5
+ class Mapper
6
+ # Define mapping a generated twirp class and your controller
7
+ module Twirp
8
+ def twirp(service_class, controller:)
9
+ service_class.rpcs.each do |_, rpcdef|
10
+ path = [service_class.service_full_name, rpcdef[:rpc_method]].join('/')
11
+ action = [controller, rpcdef[:ruby_method]].join('#')
12
+ match path, to: action, via: :post
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_dispatch/routing/mapper/twirp'
4
+
5
+ module ActionDispatch
6
+ module Twirp
7
+ class Railtie < ::Rails::Railtie # :nodoc:
8
+ initializer 'action_dispatch.twirp' do
9
+ ActionDispatch::Routing::Mapper.prepend(ActionDispatch::Routing::Mapper::Twirp)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :action_controller_twirp do
4
+ # # Task goes here
5
+ # end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_controller-twirp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kosuke Arisawa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: twirp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.36.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.36.0
55
+ description: You can implement twirp service with Rails controller
56
+ email:
57
+ - arisawa@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/action_controller/twirp.rb
66
+ - lib/action_controller/twirp/railtie.rb
67
+ - lib/action_controller/twirp/twirp_error_renderer.rb
68
+ - lib/action_controller/twirp/version.rb
69
+ - lib/action_dispatch/routing/mapper/twirp.rb
70
+ - lib/action_dispatch/twirp/railtie.rb
71
+ - lib/tasks/action_controller/twirp_tasks.rake
72
+ homepage: https://github.com/arisawa/action_controller-twirp
73
+ licenses:
74
+ - MIT
75
+ metadata:
76
+ homepage_uri: https://github.com/arisawa/action_controller-twirp
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.2.32
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Twirp for Rails Controller
96
+ test_files: []