rails_twirp 0.11.0 → 0.12.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: 9dc494fd35fa5a920f6ca55c6a024f73bda616a10cc91336fefb3d7520f9c3ed
4
- data.tar.gz: 5da02487fde28997da7fb200c0a9693fc952fc5662a2e43864d0a12c788ec7d5
3
+ metadata.gz: '09e97be65f570cd7a2cecaaf0ef83d2ead287fd1fc8c556b833ae45395ee1c2b'
4
+ data.tar.gz: 1b30d280c8c724747b0b71ef7996ad23fd0a8e189818156602f284677ac9c637
5
5
  SHA512:
6
- metadata.gz: e67eba63003648f4ba6cbc604e4e2006783c5f2873e95745f56bb1f9cfea0660d1f55850b4128b088728f829ef41989c634839b6168d5a512480e465631a60e0
7
- data.tar.gz: 163e1cd73f34ed7ee62a531c71b6a5153c35231b731645ceba25e22f37e45d94f0a51fc1ff220928eb33d2297964f108cb71696779ea958cd80dc0e4410fe462
6
+ metadata.gz: 858ea0680c3efd03f2f1fdc766f6097b6e0a7b19ff39974412207139cd28a432d4c620a7a4f9243b63b9f70eff1919cb5a92d0c3dc6b5cd73ba99eb1349ac870
7
+ data.tar.gz: ba6311d0b7cb64755380eff9d1168d24458d5804f36acf21c7fceab2a8b0db305722353d8c5f493bf1692225f973342e3194f825d995df286802da6958631e3a
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ### 0.12.0
2
+
3
+ * Allow a custom exception handling proc to be assigned using `RailsTwirp.unhandled_exception_handler`
4
+
5
+ ### 0.11.0
6
+
7
+ * Update configuration and tests for Rails 7 compatibility
8
+
9
+ ### 0.10.0
10
+
11
+ * Handle exceptions more like the Rails controllers do it, do not capture all of them as if they were Twirp exceptions
data/README.md CHANGED
@@ -1,8 +1,56 @@
1
1
  # RailsTwirp
2
- Short description and motivation.
2
+
3
+ Allows for effortless integration of [Twirp](https://github.com/twitchtv/twirp) endpoints into your Rails application. RailsTwirp permits you to define your Twirp endpoints using the familiar vocabulary of Rails routes, controllers, actions and views.
4
+
5
+ Using an extra routes file you map your Twirp RPCs to controllers, and define your views using [pbbuilder.](https://github.com/cheddar-me/pbbuilder) Even though you are now serving Twirp RPC endpoints instead of HTML or JSON, all the skills and tools you have for working your usual Rails infrastructure apply. `TwirpRails` provides a customised controller superclass called `RailsTwirp::Base` which includes all the relevant ActionController components which still make sense when using Protobufs.
3
6
 
4
7
  ## Usage
5
- How to use my plugin.
8
+
9
+ Add the gem to your project (see "Installation" below). Then add a file called `config/twirp/routes.rb` to your application, and map your RPCs inside of that file. We will map a `GreetWorld` RPC call as an example:
10
+
11
+ ```ruby
12
+ Rails.application.twirp.routes.draw do
13
+ service HelloService, module: :api do
14
+ rpc "GreetWorld", to: "greetings#greet"
15
+ end
16
+ end
17
+ ```
18
+
19
+ The `module` defines the module which will contain your `TwirpRails` controller. The `HelloService` module is your Protobuf mapping generated using Twirp, it inherits from `Twirp::Service` and could look like this:
20
+
21
+ ```ruby
22
+ class HelloService < Twirp::Service
23
+ package 'api'
24
+ service 'App'
25
+ rpc :GreetWorld, GreetWorldRequest, GreetWorldResponse, :ruby_method => :greet_world
26
+ end
27
+ ```
28
+
29
+ The `GreetWorldRequest` in this case is the autogenerated protobuf request class, the `GreetWorldResponse` is the response class.
30
+
31
+ Then you define your controller, which looks like a standard Rails controller - just with a different base class:
32
+
33
+ ```ruby
34
+ class API::GreetingsController < RailsTwirp::Base
35
+ def greet
36
+ render pb: API::GreetResponse.new
37
+ end
38
+ end
39
+ ```
40
+
41
+ Note that the controller is routed using the same naming conventions as Rails. Inside of a `TwirpRails` controller you can do most of the things you are used to from Rails controllers, such as renders and implicit renders - which have to be `pbbuilder` views. If our `GreetWorldResponse` has a `greeting` field, it can be filled inside the `pbbuilder` view like so:
42
+
43
+ ```ruby
44
+ pb.greeting "Hello stranger"
45
+ ```
46
+
47
+ Inside the controllers you have access to the call parameters of your RPC call using `request`:
48
+
49
+ ```ruby
50
+ def greet
51
+ request.name #=> # Returns the value of the "name" field from the request Protobuf
52
+ end
53
+ ```
6
54
 
7
55
  ## Installation
8
56
  Add this line to your application's Gemfile:
@@ -37,7 +85,14 @@ end
37
85
  ```
38
86
 
39
87
  ## Contributing
40
- Contribution directions go here.
88
+
89
+ * Check out the latest `main` to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
90
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
91
+ * Fork the project.
92
+ * Start a feature/bugfix branch.
93
+ * Commit and push until you are happy with your contribution.
94
+ * Make sure to add tests for your change. This is important so we don't break it in a future version unintentionally.
95
+ * Please try not to mess with the Rakefile, version, or history.
41
96
 
42
97
  ## License
43
98
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -9,17 +9,27 @@ module RailsTwirp
9
9
  def process_action(*)
10
10
  super
11
11
  rescue Exception => e
12
+ # Only the exceptions which are not captured by ActionController-like "rescue_from" end up here.
13
+ # The idea is that any exception which is rescued by the controller is treated as part of the business
14
+ # logic, and thus taking action on it is the responsibility of the controller which uses "rescue_from".
15
+ # If an exception ends up here it means it wasn't captured by the handlers defined in the controller.
16
+
12
17
  # We adopt the same error handling logic as Rails' standard middlewares:
13
18
  # 1. When we 'show exceptions' we make the exception bubble up—this is useful for testing
19
+ # If the exception gets raised here error reporting will happen in the middleware of the APM package
20
+ # higher in the call stack.
14
21
  raise e unless http_request.show_exceptions?
15
22
 
16
- # 2. When we want to show detailed exceptions we include the exception message in the error
23
+ # 2. We report the error to the error tracking service, this needs to be configured.
24
+ RailsTwirp.unhandled_exception_handler&.call(e)
25
+
26
+ # 3. When we want to show detailed exceptions we include the exception message in the error
17
27
  if http_request.get_header("action_dispatch.show_detailed_exceptions")
18
28
  self.response_body = Twirp::Error.internal_with(e)
19
29
  return
20
30
  end
21
31
 
22
- # 3. Otherwise we just return a vague internal error message
32
+ # 4. Otherwise we just return a vague internal error message
23
33
  self.response_body = Twirp::Error.internal("Internal error")
24
34
  end
25
35
  end
@@ -1,3 +1,3 @@
1
1
  module RailsTwirp
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
data/lib/rails_twirp.rb CHANGED
@@ -8,6 +8,7 @@ require "rails_twirp/log_subscriber"
8
8
 
9
9
  module RailsTwirp
10
10
  mattr_accessor :test_app
11
+ mattr_accessor :unhandled_exception_handler
11
12
  end
12
13
 
13
14
  require "rails_twirp/engine" if defined?(Rails)
@@ -66,6 +66,24 @@ class PingControllerTest < RailsTwirp::IntegrationTest
66
66
  Rails.application.env_config["action_dispatch.show_exceptions"] = false
67
67
  end
68
68
 
69
+ test "uncaught errors should be fanned out to the exception handler proc if one is defined" do
70
+ Rails.application.env_config["action_dispatch.show_exceptions"] = true
71
+
72
+ captured_exception = nil
73
+ RailsTwirp.unhandled_exception_handler = ->(e) { captured_exception = e }
74
+
75
+ req = RPC::DummyAPI::PingRequest.new
76
+ rpc RPC::DummyAPI::DummyService, "UncaughtError", req
77
+ assert_instance_of Twirp::Error, response
78
+ assert_equal :internal, response.code
79
+ assert_equal "Uncaught", response.msg
80
+ assert_equal "StandardError", response.meta["cause"]
81
+ assert_kind_of StandardError, captured_exception
82
+ ensure
83
+ RailsTwirp.unhandled_exception_handler = nil
84
+ Rails.application.env_config["action_dispatch.show_exceptions"] = false
85
+ end
86
+
69
87
  test "uncaught errors should return an internal error without if show_exceptions is true and show_detailed_exceptions is false" do
70
88
  Rails.application.env_config["action_dispatch.show_exceptions"] = true
71
89
  Rails.application.env_config["action_dispatch.show_detailed_exceptions"] = false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_twirp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bouke van der Bijl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -56,6 +56,7 @@ files:
56
56
  - ".gitignore"
57
57
  - ".ruby-version"
58
58
  - ".standard.yml"
59
+ - CHANGELOG.md
59
60
  - Gemfile
60
61
  - MIT-LICENSE
61
62
  - README.md