grape 1.4.0 → 1.5.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 +19 -3
- data/README.md +56 -8
- data/UPGRADING.md +43 -4
- data/lib/grape/api.rb +2 -2
- data/lib/grape/dsl/helpers.rb +1 -0
- data/lib/grape/dsl/inside_route.rb +26 -38
- data/lib/grape/dsl/routing.rb +2 -4
- data/lib/grape/middleware/base.rb +2 -1
- data/lib/grape/middleware/error.rb +10 -12
- data/lib/grape/middleware/stack.rb +17 -4
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router.rb +1 -1
- data/lib/grape/router/attribute_translator.rb +2 -2
- data/lib/grape/util/base_inheritable.rb +2 -2
- data/lib/grape/util/lazy_value.rb +1 -0
- data/lib/grape/validations/params_scope.rb +2 -1
- data/lib/grape/validations/types/custom_type_coercer.rb +13 -1
- data/lib/grape/validations/validators/as.rb +1 -1
- data/lib/grape/validations/validators/base.rb +2 -4
- data/lib/grape/validations/validators/default.rb +3 -4
- data/lib/grape/validations/validators/except_values.rb +1 -1
- data/lib/grape/validations/validators/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +10 -0
- data/spec/grape/dsl/inside_route_spec.rb +7 -0
- data/spec/grape/endpoint/declared_spec.rb +590 -0
- data/spec/grape/endpoint_spec.rb +0 -534
- data/spec/grape/entity_spec.rb +6 -0
- data/spec/grape/middleware/error_spec.rb +1 -1
- data/spec/grape/middleware/stack_spec.rb +3 -1
- data/spec/grape/validations/params_scope_spec.rb +26 -0
- data/spec/grape/validations/validators/coerce_spec.rb +24 -0
- data/spec/grape/validations/validators/default_spec.rb +49 -0
- data/spec/grape/validations/validators/except_values_spec.rb +1 -0
- data/spec/spec_helper.rb +0 -10
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +3 -5
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f34ddc6f9f11346067b19a6d7f8e333e433a14c1866e68714815a9e8a457487a
|
4
|
+
data.tar.gz: c95b6956bcb2e5f2e61035ec4af7ee3dcaaa53f7743bde69e7363c9a24edc317
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fef19eceff9814554a70cc0fa04d24e2cdbbba91af8f663a07a3278694c4cda2664b521d5390a57f8f1ccf7dc41dff85d602423d47aa27c87ca7d73b9d6e64ba
|
7
|
+
data.tar.gz: f1b2f404754216ba613e0250a6788ce9bbd02bd0560f2981c1847ca917398ede0f429ae03cdaf31bd3447e20248310f4ba7837511fe811ceb4ddee3b7c59df23
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
### 1.5.0 (2020/10/05)
|
2
|
+
|
3
|
+
#### Fixes
|
4
|
+
|
5
|
+
* [#2104](https://github.com/ruby-grape/grape/pull/2104): Fix Ruby 2.7 keyword deprecation warning - [@stanhu](https://github.com/stanhu).
|
6
|
+
* [#2103](https://github.com/ruby-grape/grape/pull/2103): Ensure complete declared params structure is present - [@tlconnor](https://github.com/tlconnor).
|
7
|
+
* [#2099](https://github.com/ruby-grape/grape/pull/2099): Added truffleruby to Travis-CI - [@gogainda](https://github.com/gogainda).
|
8
|
+
* [#2089](https://github.com/ruby-grape/grape/pull/2089): Specify order of mounting Grape with Rack::Cascade in README - [@jonmchan](https://github.com/jonmchan).
|
9
|
+
* [#2083](https://github.com/ruby-grape/grape/pull/2083): Set `Cache-Control` header only for streamed responses - [@stanhu](https://github.com/stanhu).
|
10
|
+
* [#2092](https://github.com/ruby-grape/grape/pull/2092): Correct an example params in Include Missing doc - [@huyvohcmc](https://github.com/huyvohcmc).
|
11
|
+
* [#2091](https://github.com/ruby-grape/grape/pull/2091): Fix ruby 2.7 keyword deprecations - [@dim](https://github.com/dim).
|
12
|
+
* [#2097](https://github.com/ruby-grape/grape/pull/2097): Skip to set default value unless `meets_dependency?` - [@wanabe](https://github.com/wanabe).
|
13
|
+
* [#2096](https://github.com/ruby-grape/grape/pull/2096): Fix redundant dependency check - [@braktar](https://github.com/braktar).
|
14
|
+
* [#2096](https://github.com/ruby-grape/grape/pull/2098): Fix nested coercion - [@braktar](https://github.com/braktar).
|
15
|
+
* [#2102](https://github.com/ruby-grape/grape/pull/2102): Fix retaining setup blocks when remounting APIs - [@jylamont](https://github.com/jylamont).
|
16
|
+
|
1
17
|
### 1.4.0 (2020/07/10)
|
2
18
|
|
3
19
|
#### Features
|
@@ -6,14 +22,14 @@
|
|
6
22
|
* [#2060](https://github.com/ruby-grape/grape/pull/2060): Drop support for Ruby 2.4 - [@dblock](https://github.com/dblock).
|
7
23
|
* [#2060](https://github.com/ruby-grape/grape/pull/2060): Upgraded Rubocop to 0.84.0 - [@dblock](https://github.com/dblock).
|
8
24
|
* [#2077](https://github.com/ruby-grape/grape/pull/2077): Simplify logic for defining declared params - [@dnesteryuk](https://github.com/dnesteryuk).
|
9
|
-
* [#
|
25
|
+
* [#2076](https://github.com/ruby-grape/grape/pull/2076): Make route information available for hooks when the automatically generated endpoints are invoked - [@anakinj](https://github.com/anakinj).
|
10
26
|
|
11
27
|
#### Fixes
|
12
28
|
|
13
|
-
* [#2067](https://github.com/ruby-grape/grape/pull/2067): Coerce empty
|
29
|
+
* [#2067](https://github.com/ruby-grape/grape/pull/2067): Coerce empty String to `nil` for all primitive types except `String` - [@petekinnecom](https://github.com/petekinnecom).
|
14
30
|
* [#2064](https://github.com/ruby-grape/grape/pull/2064): Fix Ruby 2.7 deprecation warning in `Grape::Middleware::Base#initialize` - [@skarger](https://github.com/skarger).
|
15
31
|
* [#2072](https://github.com/ruby-grape/grape/pull/2072): Fix `Grape.eager_load!` and `compile!` - [@stanhu](https://github.com/stanhu).
|
16
|
-
* [#
|
32
|
+
* [#2084](https://github.com/ruby-grape/grape/pull/2084): Fix memory leak in path normalization - [@fcheung](https://github.com/fcheung).
|
17
33
|
|
18
34
|
### 1.3.3 (2020/05/23)
|
19
35
|
|
data/README.md
CHANGED
@@ -156,7 +156,7 @@ content negotiation, versioning and much more.
|
|
156
156
|
|
157
157
|
## Stable Release
|
158
158
|
|
159
|
-
You're reading the documentation for the stable release of Grape, 1.
|
159
|
+
You're reading the documentation for the stable release of Grape, 1.5.0.
|
160
160
|
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
161
161
|
|
162
162
|
## Project Resources
|
@@ -349,9 +349,12 @@ class Web < Sinatra::Base
|
|
349
349
|
end
|
350
350
|
|
351
351
|
use Rack::Session::Cookie
|
352
|
-
run Rack::Cascade.new [
|
352
|
+
run Rack::Cascade.new [Web, API]
|
353
353
|
```
|
354
354
|
|
355
|
+
Note that order of loading apps using `Rack::Cascade` matters. The grape application must be last if you want to raise custom 404 errors from grape (such as `error!('Not Found',404)`). If the grape application is not last and returns 404 or 405 response, [cascade utilizes that as a signal to try the next app](https://www.rubydoc.info/gems/rack/Rack/Cascade). This may lead to undesirable behavior showing the [wrong 404 page from the wrong app](https://github.com/ruby-grape/grape/issues/1515).
|
356
|
+
|
357
|
+
|
355
358
|
### Rails
|
356
359
|
|
357
360
|
Place API files into `app/api`. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for `Twitter::API` should be `app/api/twitter/api.rb`.
|
@@ -783,7 +786,12 @@ Available parameter builders are `Grape::Extensions::Hash::ParamBuilder`, `Grape
|
|
783
786
|
|
784
787
|
### Declared
|
785
788
|
|
786
|
-
Grape allows you to access only the parameters that have been declared by your `params` block. It
|
789
|
+
Grape allows you to access only the parameters that have been declared by your `params` block. It will:
|
790
|
+
|
791
|
+
* Filter out the params that have been passed, but are not allowed.
|
792
|
+
* Include any optional params that are declared but not passed.
|
793
|
+
|
794
|
+
Consider the following API endpoint:
|
787
795
|
|
788
796
|
````ruby
|
789
797
|
format :json
|
@@ -816,9 +824,9 @@ Once we add parameters requirements, grape will start returning only the declare
|
|
816
824
|
format :json
|
817
825
|
|
818
826
|
params do
|
819
|
-
|
820
|
-
|
821
|
-
|
827
|
+
optional :user, type: Hash do
|
828
|
+
optional :first_name, type: String
|
829
|
+
optional :last_name, type: String
|
822
830
|
end
|
823
831
|
end
|
824
832
|
|
@@ -846,6 +854,44 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
|
|
846
854
|
}
|
847
855
|
````
|
848
856
|
|
857
|
+
Missing params that are declared as type `Hash` or `Array` will be included.
|
858
|
+
|
859
|
+
````ruby
|
860
|
+
format :json
|
861
|
+
|
862
|
+
params do
|
863
|
+
optional :user, type: Hash do
|
864
|
+
optional :first_name, type: String
|
865
|
+
optional :last_name, type: String
|
866
|
+
end
|
867
|
+
optional :widgets, type: Array
|
868
|
+
end
|
869
|
+
|
870
|
+
post 'users/signup' do
|
871
|
+
{ 'declared_params' => declared(params) }
|
872
|
+
end
|
873
|
+
````
|
874
|
+
|
875
|
+
**Request**
|
876
|
+
|
877
|
+
````bash
|
878
|
+
curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{}'
|
879
|
+
````
|
880
|
+
|
881
|
+
**Response**
|
882
|
+
|
883
|
+
````json
|
884
|
+
{
|
885
|
+
"declared_params": {
|
886
|
+
"user": {
|
887
|
+
"first_name": null,
|
888
|
+
"last_name": null
|
889
|
+
},
|
890
|
+
"widgets": []
|
891
|
+
}
|
892
|
+
}
|
893
|
+
````
|
894
|
+
|
849
895
|
The returned hash is an `ActiveSupport::HashWithIndifferentAccess`.
|
850
896
|
|
851
897
|
The `#declared` method is not available to `before` filters, as those are evaluated prior to parameter coercion.
|
@@ -904,8 +950,10 @@ By default `declared(params)` includes parameters that have `nil` values. If you
|
|
904
950
|
format :json
|
905
951
|
|
906
952
|
params do
|
907
|
-
requires :
|
908
|
-
|
953
|
+
requires :user, type: Hash do
|
954
|
+
requires :first_name, type: String
|
955
|
+
optional :last_name, type: String
|
956
|
+
end
|
909
957
|
end
|
910
958
|
|
911
959
|
post 'users/signup' do
|
data/UPGRADING.md
CHANGED
@@ -1,6 +1,45 @@
|
|
1
1
|
Upgrading Grape
|
2
2
|
===============
|
3
3
|
|
4
|
+
### Upgrading to >= 1.5.0
|
5
|
+
|
6
|
+
Prior to 1.3.3, the `declared` helper would always return the complete params structure if `include_missing=true` was set. In 1.3.3 a regression was introduced such that a missing Hash with or without nested parameters would always resolve to `{}`.
|
7
|
+
|
8
|
+
In 1.5.0 this behavior is reverted, so the whole params structure will always be available via `declared`, regardless of whether any params are passed.
|
9
|
+
|
10
|
+
The following rules now apply to the `declared` helper when params are missing and `include_missing=true`:
|
11
|
+
|
12
|
+
* Hash params with children will resolve to a Hash with keys for each declared child.
|
13
|
+
* Hash params with no children will resolve to `{}`.
|
14
|
+
* Set params will resolve to `Set.new`.
|
15
|
+
* Array params will resolve to `[]`.
|
16
|
+
* All other params will resolve to `nil`.
|
17
|
+
|
18
|
+
#### Example
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class Api < Grape::API
|
22
|
+
params do
|
23
|
+
optional :outer, type: Hash do
|
24
|
+
optional :inner, type: Hash do
|
25
|
+
optional :value, type: String
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
get 'example' do
|
30
|
+
declared(params, include_missing: true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
```
|
36
|
+
get '/example'
|
37
|
+
# 1.3.3 = {}
|
38
|
+
# 1.5.0 = {outer: {inner: {value:null}}}
|
39
|
+
```
|
40
|
+
|
41
|
+
For more information see [#2103](https://github.com/ruby-grape/grape/pull/2103).
|
42
|
+
|
4
43
|
### Upgrading to >= 1.4.0
|
5
44
|
|
6
45
|
#### Reworking stream and file and un-deprecating stream like-objects
|
@@ -28,17 +67,17 @@ class API < Grape::API
|
|
28
67
|
end
|
29
68
|
```
|
30
69
|
|
31
|
-
Or use `stream` to stream other kinds of content. In the following example a streamer class
|
70
|
+
Or use `stream` to stream other kinds of content. In the following example a streamer class
|
32
71
|
streams paginated data from a database.
|
33
72
|
|
34
73
|
```ruby
|
35
|
-
class MyObject
|
74
|
+
class MyObject
|
36
75
|
attr_accessor :result
|
37
76
|
|
38
77
|
def initialize(query)
|
39
78
|
@result = query
|
40
79
|
end
|
41
|
-
|
80
|
+
|
42
81
|
def each
|
43
82
|
yield '['
|
44
83
|
# Do paginated DB fetches and return each page formatted
|
@@ -47,7 +86,7 @@ class MyObject
|
|
47
86
|
yield process_records(records, first)
|
48
87
|
first = false
|
49
88
|
end
|
50
|
-
yield ']'
|
89
|
+
yield ']'
|
51
90
|
end
|
52
91
|
|
53
92
|
def process_records(records, first)
|
data/lib/grape/api.rb
CHANGED
@@ -30,7 +30,7 @@ module Grape
|
|
30
30
|
# an instance that will be used to create the set up but will not be mounted
|
31
31
|
def initial_setup(base_instance_parent)
|
32
32
|
@instances = []
|
33
|
-
@setup =
|
33
|
+
@setup = Set.new
|
34
34
|
@base_parent = base_instance_parent
|
35
35
|
@base_instance = mount_instance
|
36
36
|
end
|
@@ -90,7 +90,7 @@ module Grape
|
|
90
90
|
# For instance, a descripcion could be done using: `desc configuration[:description]` if it may vary
|
91
91
|
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
92
92
|
# too much, you may actually want to provide a new API rather than remount it.
|
93
|
-
def mount_instance(opts
|
93
|
+
def mount_instance(**opts)
|
94
94
|
instance = Class.new(@base_parent)
|
95
95
|
instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
|
96
96
|
instance.base = self
|
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -58,7 +58,7 @@ module Grape
|
|
58
58
|
passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
|
59
59
|
memo_key = optioned_param_key(declared_parent_param, options)
|
60
60
|
|
61
|
-
memo[memo_key] = handle_passed_param(
|
61
|
+
memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
|
62
62
|
declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
|
63
63
|
end
|
64
64
|
end
|
@@ -70,57 +70,43 @@ module Grape
|
|
70
70
|
|
71
71
|
next unless options[:include_missing] || passed_params.key?(declared_param) || (param_renaming && passed_params.key?(param_renaming))
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
memo_key = optioned_param_key(param_renaming || declared_param, options)
|
74
|
+
passed_param = passed_params[param_renaming || declared_param]
|
75
|
+
|
76
|
+
params_nested_path_dup = params_nested_path.dup
|
77
|
+
params_nested_path_dup << declared_param.to_s
|
78
|
+
memo[memo_key] = passed_param || handle_passed_param(params_nested_path_dup) do
|
79
|
+
passed_param
|
77
80
|
end
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
def handle_passed_param(
|
83
|
-
if
|
85
|
+
def handle_passed_param(params_nested_path, has_passed_children = false, &_block)
|
86
|
+
return yield if has_passed_children
|
87
|
+
|
88
|
+
key = params_nested_path[0]
|
89
|
+
key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
|
90
|
+
|
91
|
+
route_options_params = options[:route_options][:params] || {}
|
92
|
+
type = route_options_params.dig(key, :type)
|
93
|
+
has_children = route_options_params.keys.any? { |k| k != key && k.start_with?(key) }
|
94
|
+
|
95
|
+
if type == 'Hash' && !has_children
|
84
96
|
{}
|
85
|
-
elsif
|
97
|
+
elsif type == 'Array' || type&.start_with?('[')
|
86
98
|
[]
|
99
|
+
elsif type == 'Set' || type&.start_with?('#<Set')
|
100
|
+
Set.new
|
87
101
|
else
|
88
102
|
yield
|
89
103
|
end
|
90
104
|
end
|
91
105
|
|
92
|
-
def should_be_empty_array?(passed_children_params, params_nested_path)
|
93
|
-
passed_children_params.empty? && declared_param_is_array?(params_nested_path)
|
94
|
-
end
|
95
|
-
|
96
|
-
def declared_param_is_array?(params_nested_path)
|
97
|
-
key = route_options_params_key(params_nested_path)
|
98
|
-
route_options_params[key] && route_options_params[key][:type] == 'Array'
|
99
|
-
end
|
100
|
-
|
101
|
-
def should_be_empty_hash?(passed_children_params, params_nested_path)
|
102
|
-
passed_children_params.empty? && declared_param_is_hash?(params_nested_path)
|
103
|
-
end
|
104
|
-
|
105
|
-
def declared_param_is_hash?(params_nested_path)
|
106
|
-
key = route_options_params_key(params_nested_path)
|
107
|
-
route_options_params[key] && route_options_params[key][:type] == 'Hash'
|
108
|
-
end
|
109
|
-
|
110
|
-
def route_options_params
|
111
|
-
options[:route_options][:params] || {}
|
112
|
-
end
|
113
|
-
|
114
106
|
def optioned_param_key(declared_param, options)
|
115
107
|
options[:stringify] ? declared_param.to_s : declared_param.to_sym
|
116
108
|
end
|
117
109
|
|
118
|
-
def route_options_params_key(params_nested_path)
|
119
|
-
key = params_nested_path[0]
|
120
|
-
key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
|
121
|
-
key
|
122
|
-
end
|
123
|
-
|
124
110
|
def optioned_declared_params(**options)
|
125
111
|
declared_params = if options[:include_parent_namespaces]
|
126
112
|
# Declared params including parent namespaces
|
@@ -328,6 +314,8 @@ module Grape
|
|
328
314
|
# * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/chunked.rb
|
329
315
|
# * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/etag.rb
|
330
316
|
def stream(value = nil)
|
317
|
+
return if value.nil? && @stream.nil?
|
318
|
+
|
331
319
|
header 'Content-Length', nil
|
332
320
|
header 'Transfer-Encoding', nil
|
333
321
|
header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
|
@@ -339,7 +327,7 @@ module Grape
|
|
339
327
|
elsif !value.is_a?(NilClass)
|
340
328
|
raise ArgumentError, 'Stream object must respond to :each.'
|
341
329
|
else
|
342
|
-
|
330
|
+
@stream
|
343
331
|
end
|
344
332
|
end
|
345
333
|
|
@@ -433,7 +421,7 @@ module Grape
|
|
433
421
|
def entity_representation_for(entity_class, object, options)
|
434
422
|
embeds = { env: env }
|
435
423
|
embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
|
436
|
-
entity_class.represent(object, embeds.merge(options))
|
424
|
+
entity_class.represent(object, **embeds.merge(options))
|
437
425
|
end
|
438
426
|
end
|
439
427
|
end
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -79,7 +79,7 @@ module Grape
|
|
79
79
|
namespace_inheritable(:do_not_route_options, true)
|
80
80
|
end
|
81
81
|
|
82
|
-
def mount(mounts, opts
|
82
|
+
def mount(mounts, **opts)
|
83
83
|
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
|
84
84
|
mounts.each_pair do |app, path|
|
85
85
|
if app.respond_to?(:mount_instance)
|
@@ -170,9 +170,7 @@ module Grape
|
|
170
170
|
previous_namespace_description = @namespace_description
|
171
171
|
@namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
|
172
172
|
nest(block) do
|
173
|
-
if space
|
174
|
-
namespace_stackable(:namespace, Namespace.new(space, **options))
|
175
|
-
end
|
173
|
+
namespace_stackable(:namespace, Namespace.new(space, **options)) if space
|
176
174
|
end
|
177
175
|
@namespace_description = previous_namespace_description
|
178
176
|
end
|
@@ -8,13 +8,14 @@ module Grape
|
|
8
8
|
include Helpers
|
9
9
|
|
10
10
|
attr_reader :app, :env, :options
|
11
|
+
|
11
12
|
TEXT_HTML = 'text/html'
|
12
13
|
|
13
14
|
include Grape::DSL::Headers
|
14
15
|
|
15
16
|
# @param [Rack Application] app The standard argument for a Rack middleware.
|
16
17
|
# @param [Hash] options A hash of options, simply stored for use by subclasses.
|
17
|
-
def initialize(app, options
|
18
|
+
def initialize(app, **options)
|
18
19
|
@app = app
|
19
20
|
@options = default_options.merge(options)
|
20
21
|
@app_response = nil
|
@@ -19,11 +19,11 @@ module Grape
|
|
19
19
|
rescue_subclasses: true, # rescue subclasses of exceptions listed
|
20
20
|
rescue_options: {
|
21
21
|
backtrace: false, # true to display backtrace, true to let Grape handle Grape::Exceptions
|
22
|
-
original_exception: false
|
22
|
+
original_exception: false # true to display exception
|
23
23
|
},
|
24
24
|
rescue_handlers: {}, # rescue handler blocks
|
25
25
|
base_only_rescue_handlers: {}, # rescue handler blocks rescuing only the base class
|
26
|
-
all_rescue_handler: nil
|
26
|
+
all_rescue_handler: nil # rescue handler block to rescue from all exceptions
|
27
27
|
}
|
28
28
|
end
|
29
29
|
|
@@ -38,15 +38,15 @@ module Grape
|
|
38
38
|
error_response(catch(:error) do
|
39
39
|
return @app.call(@env)
|
40
40
|
end)
|
41
|
-
rescue Exception =>
|
41
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
42
42
|
handler =
|
43
|
-
rescue_handler_for_base_only_class(
|
44
|
-
rescue_handler_for_class_or_its_ancestor(
|
45
|
-
rescue_handler_for_grape_exception(
|
46
|
-
rescue_handler_for_any_class(
|
43
|
+
rescue_handler_for_base_only_class(e.class) ||
|
44
|
+
rescue_handler_for_class_or_its_ancestor(e.class) ||
|
45
|
+
rescue_handler_for_grape_exception(e.class) ||
|
46
|
+
rescue_handler_for_any_class(e.class) ||
|
47
47
|
raise
|
48
48
|
|
49
|
-
run_rescue_handler(handler,
|
49
|
+
run_rescue_handler(handler, e)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -65,15 +65,13 @@ module Grape
|
|
65
65
|
message = error[:message] || options[:default_message]
|
66
66
|
headers = { Grape::Http::Headers::CONTENT_TYPE => content_type }
|
67
67
|
headers.merge!(error[:headers]) if error[:headers].is_a?(Hash)
|
68
|
-
backtrace = error[:backtrace] || error[:original_exception]
|
68
|
+
backtrace = error[:backtrace] || error[:original_exception]&.backtrace || []
|
69
69
|
original_exception = error.is_a?(Exception) ? error : error[:original_exception] || nil
|
70
70
|
rack_response(format_message(message, backtrace, original_exception), status, headers)
|
71
71
|
end
|
72
72
|
|
73
73
|
def rack_response(message, status = options[:default_status], headers = { Grape::Http::Headers::CONTENT_TYPE => content_type })
|
74
|
-
if headers[Grape::Http::Headers::CONTENT_TYPE] == TEXT_HTML
|
75
|
-
message = ERB::Util.html_escape(message)
|
76
|
-
end
|
74
|
+
message = ERB::Util.html_escape(message) if headers[Grape::Http::Headers::CONTENT_TYPE] == TEXT_HTML
|
77
75
|
Rack::Response.new([message], status, headers)
|
78
76
|
end
|
79
77
|
|