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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +58 -3
- data/lib/rails_twirp/exception_handling.rb +12 -2
- data/lib/rails_twirp/version.rb +1 -1
- data/lib/rails_twirp.rb +1 -0
- data/test/ping_controller_test.rb +18 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09e97be65f570cd7a2cecaaf0ef83d2ead287fd1fc8c556b833ae45395ee1c2b'
|
4
|
+
data.tar.gz: 1b30d280c8c724747b0b71ef7996ad23fd0a8e189818156602f284677ac9c637
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
#
|
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
|
data/lib/rails_twirp/version.rb
CHANGED
data/lib/rails_twirp.rb
CHANGED
@@ -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.
|
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-
|
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
|