grape 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|