grape 2.1.0 → 2.2.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 +46 -0
- data/README.md +4 -3
- data/UPGRADING.md +8 -0
- data/grape.gemspec +2 -1
- data/lib/grape/api/instance.rb +1 -1
- data/lib/grape/api.rb +2 -2
- data/lib/grape/content_types.rb +13 -8
- data/lib/grape/dsl/helpers.rb +7 -3
- data/lib/grape/dsl/inside_route.rb +14 -3
- data/lib/grape/dsl/parameters.rb +1 -1
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/endpoint.rb +34 -23
- data/lib/grape/error_formatter/json.rb +13 -4
- data/lib/grape/error_formatter.rb +13 -25
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter.rb +15 -25
- data/lib/grape/locale/en.yml +1 -0
- data/lib/grape/middleware/base.rb +14 -13
- data/lib/grape/middleware/error.rb +13 -11
- data/lib/grape/middleware/formatter.rb +2 -2
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +8 -31
- data/lib/grape/middleware/versioner/header.rb +95 -10
- data/lib/grape/middleware/versioner/param.rb +5 -21
- data/lib/grape/middleware/versioner/path.rb +11 -31
- data/lib/grape/middleware/versioner.rb +5 -14
- data/lib/grape/middleware/versioner_helpers.rb +75 -0
- data/lib/grape/parser.rb +8 -24
- data/lib/grape/router.rb +2 -1
- data/lib/grape/validations/attributes_iterator.rb +1 -0
- data/lib/grape/validations/params_scope.rb +12 -10
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
- data/lib/grape/validations/validators/length_validator.rb +10 -3
- data/lib/grape/version.rb +1 -1
- metadata +8 -9
- data/lib/grape/util/accept/header.rb +0 -19
- data/lib/grape/util/accept_header_handler.rb +0 -105
- data/lib/grape/util/registrable.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc04f424b8181e92cc304d02d2923952f07e2532ef0291233596813726a2cb68
|
4
|
+
data.tar.gz: 46729a20982fc16129540a81061bea229fd3ba5dd81426c1830119b52fe6ccd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45e47b5059a37bbf75331c41bb1fdda2487610e3713baf5b8181dcbbae1727c47995503f5dc8a12375fd0765908140540100579afe834dfe96dc4c07cd771b2f
|
7
|
+
data.tar.gz: 9692f64fc61714c33035ef59c0d68a9c34fb3725a5842e0fe16cbd4d7025265bef50ea5086a3f61d5ed1f0fd8740435619ff616eed55e45fd3cc48e090a02b7d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,49 @@
|
|
1
|
+
### 2.2.0 (2024-09-14)
|
2
|
+
|
3
|
+
#### Features
|
4
|
+
|
5
|
+
* [#2475](https://github.com/ruby-grape/grape/pull/2475): Remove Grape::Util::Registrable - [@ericproulx](https://github.com/ericproulx).
|
6
|
+
* [#2484](https://github.com/ruby-grape/grape/pull/2484): Refactor versioner middlewares - [@ericproulx](https://github.com/ericproulx).
|
7
|
+
* [#2489](https://github.com/ruby-grape/grape/pull/2489): Add Rails 7.2 in CI workflow - [@ericproulx](https://github.com/ericproulx).
|
8
|
+
* [#2493](https://github.com/ruby-grape/grape/pull/2493): MFA required when releasing - [@ericproulx](https://github.com/ericproulx).
|
9
|
+
|
10
|
+
#### Fixes
|
11
|
+
|
12
|
+
* [#2471](https://github.com/ruby-grape/grape/pull/2471): Fix absence of original_exception and/or backtrace even if passed in error! - [@numbata](https://github.com/numbata).
|
13
|
+
* [#2478](https://github.com/ruby-grape/grape/pull/2478): Fix rescue_from with invalid response - [@ericproulx](https://github.com/ericproulx).
|
14
|
+
* [#2480](https://github.com/ruby-grape/grape/pull/2480): Fix rescue_from ValidationErrors exception - [@numbata](https://github.com/numbata).
|
15
|
+
* [#2464](https://github.com/ruby-grape/grape/pull/2464): The `length` validator only takes effect for parameters with types that support `#length` method - [@OuYangJinTing](https://github.com/OuYangJinTing).
|
16
|
+
* [#2485](https://github.com/ruby-grape/grape/pull/2485): Add `is:` param to length validator - [@dakad](https://github.com/dakad).
|
17
|
+
* [#2492](https://github.com/ruby-grape/grape/pull/2492): Fix `Grape::Endpoint#inspect` method - [@ericproulx](https://github.com/ericproulx).
|
18
|
+
* [#2496](https://github.com/ruby-grape/grape/pull/2496): Reduce object allocation when compiling - [@ericproulx](https://github.com/ericproulx).
|
19
|
+
|
20
|
+
### 2.1.3 (2024-07-13)
|
21
|
+
|
22
|
+
#### Fixes
|
23
|
+
|
24
|
+
* [#2467](https://github.com/ruby-grape/grape/pull/2467): Fix repo coverage - [@ericproulx](https://github.com/ericproulx).
|
25
|
+
* [#2468](https://github.com/ruby-grape/grape/pull/2468): Align `error!` method signatures across different places - [@numbata](https://github.com/numbata).
|
26
|
+
* [#2469](https://github.com/ruby-grape/grape/pull/2469): Fix full path building for lateral scopes - [@numbata](https://github.com/numbata).
|
27
|
+
|
28
|
+
### 2.1.2 (2024-06-28)
|
29
|
+
|
30
|
+
#### Fixes
|
31
|
+
|
32
|
+
* [#2459](https://github.com/ruby-grape/grape/pull/2459): Autocorrect cops - [@ericproulx](https://github.com/ericproulx).
|
33
|
+
* [#3458](https://github.com/ruby-grape/grape/pull/2458): Remove unused Grape::Util::Accept::Header - [@ericproulx](https://github.com/ericproulx).
|
34
|
+
* [#2463](https://github.com/ruby-grape/grape/pull/2463): Fix error message indices - [@ericproulx](https://github.com/ericproulx).
|
35
|
+
|
36
|
+
### 2.1.1 (2024-06-22)
|
37
|
+
|
38
|
+
#### Features
|
39
|
+
|
40
|
+
* [#2450](https://github.com/ruby-grape/grape/pull/2450): Update RuboCop to 1.64.1 - [@ericproulx](https://github.com/ericproulx).
|
41
|
+
|
42
|
+
#### Fixes
|
43
|
+
|
44
|
+
* [#2453](https://github.com/ruby-grape/grape/pull/2453): Fix context in rescue_from - [@ericproulx](https://github.com/ericproulx).
|
45
|
+
* [#2455](https://github.com/ruby-grape/grape/pull/2455): Fix default response headers to work with Rack 3 - [@ericproulx](https://github.com/ericproulx).
|
46
|
+
|
1
47
|
### 2.1.0 (2024/06/15)
|
2
48
|
|
3
49
|
#### Features
|
data/README.md
CHANGED
@@ -157,8 +157,7 @@ Grape is a REST-like API framework for Ruby. It's designed to run on Rack or com
|
|
157
157
|
|
158
158
|
## Stable Release
|
159
159
|
|
160
|
-
You're reading the documentation for the stable release of Grape,
|
161
|
-
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
160
|
+
You're reading the documentation for the stable release of Grape, 2.2.0. Please read UPGRADING when upgrading from a previous version.
|
162
161
|
|
163
162
|
## Project Resources
|
164
163
|
|
@@ -1713,10 +1712,11 @@ end
|
|
1713
1712
|
|
1714
1713
|
Parameters with types that support `#length` method can be restricted to have a specific length with the `:length` option.
|
1715
1714
|
|
1716
|
-
The validator accepts `:min` or `:max` or both options to validate that the value of the parameter is within the given limits.
|
1715
|
+
The validator accepts `:min` or `:max` or both options or only `:is` to validate that the value of the parameter is within the given limits.
|
1717
1716
|
|
1718
1717
|
```ruby
|
1719
1718
|
params do
|
1719
|
+
requires :code, type: String, length: { is: 2 }
|
1720
1720
|
requires :str, type: String, length: { min: 3 }
|
1721
1721
|
requires :list, type: [Integer], length: { min: 3, max: 5 }
|
1722
1722
|
requires :hash, type: Hash, length: { max: 5 }
|
@@ -2044,6 +2044,7 @@ end
|
|
2044
2044
|
|
2045
2045
|
```ruby
|
2046
2046
|
params do
|
2047
|
+
requires :code, type: String, length: { is: 2, message: 'code is expected to be exactly 2 characters long' }
|
2047
2048
|
requires :str, type: String, length: { min: 5, message: 'str is expected to be atleast 5 characters long' }
|
2048
2049
|
requires :list, type: [Integer], length: { min: 2, max: 3, message: 'list is expected to have between 2 and 3 elements' }
|
2049
2050
|
end
|
data/UPGRADING.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
Upgrading Grape
|
2
2
|
===============
|
3
3
|
|
4
|
+
### Upgrading to >= 2.2.0
|
5
|
+
|
6
|
+
### `Length` validator
|
7
|
+
|
8
|
+
After Grape 2.2.0, `length` validator will only take effect for parameters with types that support `#length` method, will not throw `ArgumentError` exception.
|
9
|
+
|
10
|
+
See [#2464](https://github.com/ruby-grape/grape/pull/2464) for more information.
|
11
|
+
|
4
12
|
### Upgrading to >= 2.1.0
|
5
13
|
|
6
14
|
#### Optional Builder
|
data/grape.gemspec
CHANGED
@@ -17,7 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
|
18
18
|
'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
|
19
19
|
'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
|
20
|
-
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
|
20
|
+
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}",
|
21
|
+
'rubygems_mfa_required' => 'true'
|
21
22
|
}
|
22
23
|
|
23
24
|
s.add_runtime_dependency 'activesupport', '>= 6'
|
data/lib/grape/api/instance.rb
CHANGED
@@ -46,7 +46,7 @@ module Grape
|
|
46
46
|
# Parses the API's definition and compiles it into an instance of
|
47
47
|
# Grape::API.
|
48
48
|
def compile
|
49
|
-
@instance ||= new
|
49
|
+
@instance ||= new # rubocop:disable Naming/MemoizedInstanceVariableName
|
50
50
|
end
|
51
51
|
|
52
52
|
# Wipe the compiled API so we can recompile after changes were made.
|
data/lib/grape/api.rb
CHANGED
@@ -32,7 +32,7 @@ module Grape
|
|
32
32
|
def inherited(api)
|
33
33
|
super
|
34
34
|
|
35
|
-
api.initial_setup(Grape::API
|
35
|
+
api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance)
|
36
36
|
api.override_all_methods!
|
37
37
|
end
|
38
38
|
|
@@ -108,7 +108,7 @@ module Grape
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def respond_to?(method, include_private = false)
|
111
|
-
super
|
111
|
+
super || base_instance.respond_to?(method, include_private)
|
112
112
|
end
|
113
113
|
|
114
114
|
def respond_to_missing?(method, include_private = false)
|
data/lib/grape/content_types.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ContentTypes
|
5
|
-
|
5
|
+
module_function
|
6
6
|
|
7
7
|
# Content types are listed in order of preference.
|
8
|
-
|
8
|
+
DEFAULTS = {
|
9
9
|
xml: 'application/xml',
|
10
10
|
serializable_hash: 'application/json',
|
11
11
|
json: 'application/json',
|
@@ -13,13 +13,18 @@ module Grape
|
|
13
13
|
txt: 'text/plain'
|
14
14
|
}.freeze
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
MIME_TYPES = Grape::ContentTypes::DEFAULTS.except(:serializable_hash).invert.freeze
|
17
|
+
|
18
|
+
def content_types_for(from_settings)
|
19
|
+
from_settings.presence || DEFAULTS
|
20
|
+
end
|
21
|
+
|
22
|
+
def mime_types_for(from_settings)
|
23
|
+
return MIME_TYPES if from_settings == Grape::ContentTypes::DEFAULTS
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
from_settings.each_with_object({}) do |(k, v), types_without_params|
|
26
|
+
# remove optional parameter
|
27
|
+
types_without_params[v.split(';', 2).first] = k
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -33,18 +33,22 @@ module Grape
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
def helpers(*new_modules, &block)
|
36
|
-
include_new_modules(new_modules)
|
37
|
-
include_block(block)
|
36
|
+
include_new_modules(new_modules)
|
37
|
+
include_block(block)
|
38
38
|
include_all_in_scope if !block && new_modules.empty?
|
39
39
|
end
|
40
40
|
|
41
41
|
protected
|
42
42
|
|
43
43
|
def include_new_modules(modules)
|
44
|
+
return if modules.empty?
|
45
|
+
|
44
46
|
modules.each { |mod| make_inclusion(mod) }
|
45
47
|
end
|
46
48
|
|
47
49
|
def include_block(block)
|
50
|
+
return unless block
|
51
|
+
|
48
52
|
Module.new.tap do |mod|
|
49
53
|
make_inclusion(mod) { mod.class_eval(&block) }
|
50
54
|
end
|
@@ -58,7 +62,7 @@ module Grape
|
|
58
62
|
|
59
63
|
def include_all_in_scope
|
60
64
|
Module.new.tap do |mod|
|
61
|
-
namespace_stackable(:helpers).each { |mod_to_include| mod.
|
65
|
+
namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
|
62
66
|
change!
|
63
67
|
end
|
64
68
|
end
|
@@ -163,12 +163,19 @@ module Grape
|
|
163
163
|
# end user with the specified message.
|
164
164
|
#
|
165
165
|
# @param message [String] The message to display.
|
166
|
-
# @param status [Integer]
|
166
|
+
# @param status [Integer] The HTTP Status Code. Defaults to default_error_status, 500 if not set.
|
167
167
|
# @param additional_headers [Hash] Addtional headers for the response.
|
168
|
-
|
168
|
+
# @param backtrace [Array<String>] The backtrace of the exception that caused the error.
|
169
|
+
# @param original_exception [Exception] The original exception that caused the error.
|
170
|
+
def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
|
169
171
|
status = self.status(status || namespace_inheritable(:default_error_status))
|
170
172
|
headers = additional_headers.present? ? header.merge(additional_headers) : header
|
171
|
-
throw :error,
|
173
|
+
throw :error,
|
174
|
+
message: message,
|
175
|
+
status: status,
|
176
|
+
headers: headers,
|
177
|
+
backtrace: backtrace,
|
178
|
+
original_exception: original_exception
|
172
179
|
end
|
173
180
|
|
174
181
|
# Creates a Rack response based on the provided message, status, and headers.
|
@@ -461,6 +468,10 @@ module Grape
|
|
461
468
|
def http_version
|
462
469
|
env['HTTP_VERSION'] || env[Rack::SERVER_PROTOCOL]
|
463
470
|
end
|
471
|
+
|
472
|
+
def context
|
473
|
+
self
|
474
|
+
end
|
464
475
|
end
|
465
476
|
end
|
466
477
|
end
|
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -17,18 +17,16 @@ module Grape
|
|
17
17
|
# Specify the format for the API's serializers.
|
18
18
|
# May be `:json`, `:xml`, `:txt`, etc.
|
19
19
|
def format(new_format = nil)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
namespace_inheritable(:format)
|
31
|
-
end
|
20
|
+
return namespace_inheritable(:format) unless new_format
|
21
|
+
|
22
|
+
symbolic_new_format = new_format.to_sym
|
23
|
+
namespace_inheritable(:format, symbolic_new_format)
|
24
|
+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
|
25
|
+
|
26
|
+
content_type = content_types[symbolic_new_format]
|
27
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
|
28
|
+
|
29
|
+
namespace_stackable(:content_types, symbolic_new_format => content_type)
|
32
30
|
end
|
33
31
|
|
34
32
|
# Specify a custom formatter for a content-type.
|
@@ -43,12 +41,10 @@ module Grape
|
|
43
41
|
|
44
42
|
# Specify a default error formatter.
|
45
43
|
def default_error_formatter(new_formatter_name = nil)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
namespace_inheritable(:default_error_formatter)
|
51
|
-
end
|
44
|
+
return namespace_inheritable(:default_error_formatter) unless new_formatter_name
|
45
|
+
|
46
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
|
47
|
+
namespace_inheritable(:default_error_formatter, new_formatter)
|
52
48
|
end
|
53
49
|
|
54
50
|
def error_formatter(format, options)
|
data/lib/grape/endpoint.rb
CHANGED
@@ -114,10 +114,10 @@ module Grape
|
|
114
114
|
# Update our settings from a given set of stackable parameters. Used when
|
115
115
|
# the endpoint's API is mounted under another one.
|
116
116
|
def inherit_settings(namespace_stackable)
|
117
|
-
|
117
|
+
parent_validations = namespace_stackable[:validations]
|
118
|
+
inheritable_setting.route[:saved_validations].concat(parent_validations) if parent_validations.any?
|
118
119
|
parent_declared_params = namespace_stackable[:declared_params]
|
119
|
-
|
120
|
-
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params
|
120
|
+
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params.any?
|
121
121
|
|
122
122
|
endpoints&.each { |e| e.inherit_settings(namespace_stackable) }
|
123
123
|
end
|
@@ -191,8 +191,7 @@ module Grape
|
|
191
191
|
|
192
192
|
def prepare_version
|
193
193
|
version = namespace_inheritable(:version)
|
194
|
-
return
|
195
|
-
return if version.empty?
|
194
|
+
return if version.blank?
|
196
195
|
|
197
196
|
version.length == 1 ? version.first : version
|
198
197
|
end
|
@@ -206,7 +205,9 @@ module Grape
|
|
206
205
|
end
|
207
206
|
|
208
207
|
def prepare_path(path)
|
209
|
-
|
208
|
+
namespace_stackable_hash = inheritable_setting.namespace_stackable.to_hash
|
209
|
+
namespace_inheritable_hash = inheritable_setting.namespace_inheritable.to_hash
|
210
|
+
path_settings = namespace_stackable_hash.merge!(namespace_inheritable_hash)
|
210
211
|
Path.new(path, namespace, path_settings)
|
211
212
|
end
|
212
213
|
|
@@ -231,8 +232,17 @@ module Grape
|
|
231
232
|
options[:app].endpoints if options[:app].respond_to?(:endpoints)
|
232
233
|
end
|
233
234
|
|
234
|
-
def equals?(
|
235
|
-
(options ==
|
235
|
+
def equals?(endpoint)
|
236
|
+
(options == endpoint.options) && (inheritable_setting.to_hash == endpoint.inheritable_setting.to_hash)
|
237
|
+
end
|
238
|
+
|
239
|
+
# The purpose of this override is solely for stripping internals when an error occurs while calling
|
240
|
+
# an endpoint through an api. See https://github.com/ruby-grape/grape/issues/2398
|
241
|
+
# Otherwise, it calls super.
|
242
|
+
def inspect
|
243
|
+
return super unless env
|
244
|
+
|
245
|
+
"#{self.class} in '#{route.origin}' endpoint"
|
236
246
|
end
|
237
247
|
|
238
248
|
protected
|
@@ -280,36 +290,39 @@ module Grape
|
|
280
290
|
def build_stack(helpers)
|
281
291
|
stack = Grape::Middleware::Stack.new
|
282
292
|
|
293
|
+
content_types = namespace_stackable_with_hash(:content_types)
|
294
|
+
format = namespace_inheritable(:format)
|
295
|
+
|
283
296
|
stack.use Rack::Head
|
284
297
|
stack.use Class.new(Grape::Middleware::Error),
|
285
298
|
helpers: helpers,
|
286
|
-
format:
|
287
|
-
content_types:
|
299
|
+
format: format,
|
300
|
+
content_types: content_types,
|
288
301
|
default_status: namespace_inheritable(:default_error_status),
|
289
302
|
rescue_all: namespace_inheritable(:rescue_all),
|
290
303
|
rescue_grape_exceptions: namespace_inheritable(:rescue_grape_exceptions),
|
291
304
|
default_error_formatter: namespace_inheritable(:default_error_formatter),
|
292
305
|
error_formatters: namespace_stackable_with_hash(:error_formatters),
|
293
|
-
rescue_options: namespace_stackable_with_hash(:rescue_options)
|
294
|
-
rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers)
|
295
|
-
base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers)
|
306
|
+
rescue_options: namespace_stackable_with_hash(:rescue_options),
|
307
|
+
rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers),
|
308
|
+
base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers),
|
296
309
|
all_rescue_handler: namespace_inheritable(:all_rescue_handler),
|
297
310
|
grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
|
298
311
|
|
299
312
|
stack.concat namespace_stackable(:middleware)
|
300
313
|
|
301
|
-
if namespace_inheritable(:version)
|
314
|
+
if namespace_inheritable(:version).present?
|
302
315
|
stack.use Grape::Middleware::Versioner.using(namespace_inheritable(:version_options)[:using]),
|
303
|
-
versions: namespace_inheritable(:version)
|
316
|
+
versions: namespace_inheritable(:version).flatten,
|
304
317
|
version_options: namespace_inheritable(:version_options),
|
305
318
|
prefix: namespace_inheritable(:root_prefix),
|
306
319
|
mount_path: namespace_stackable(:mount_path).first
|
307
320
|
end
|
308
321
|
|
309
322
|
stack.use Grape::Middleware::Formatter,
|
310
|
-
format:
|
323
|
+
format: format,
|
311
324
|
default_format: namespace_inheritable(:default_format) || :txt,
|
312
|
-
content_types:
|
325
|
+
content_types: content_types,
|
313
326
|
formatters: namespace_stackable_with_hash(:formatters),
|
314
327
|
parsers: namespace_stackable_with_hash(:parsers)
|
315
328
|
|
@@ -320,7 +333,9 @@ module Grape
|
|
320
333
|
|
321
334
|
def build_helpers
|
322
335
|
helpers = namespace_stackable(:helpers)
|
323
|
-
|
336
|
+
return if helpers.empty?
|
337
|
+
|
338
|
+
Module.new { helpers.each { |mod_to_include| include mod_to_include } }
|
324
339
|
end
|
325
340
|
|
326
341
|
private :build_stack, :build_helpers
|
@@ -339,7 +354,7 @@ module Grape
|
|
339
354
|
@lazy_initialize_lock.synchronize do
|
340
355
|
return true if @lazy_initialized
|
341
356
|
|
342
|
-
@helpers = build_helpers
|
357
|
+
@helpers = build_helpers&.tap { |mod| self.class.include mod }
|
343
358
|
@app = options[:app] || build_stack(@helpers)
|
344
359
|
|
345
360
|
@lazy_initialized = true
|
@@ -404,9 +419,5 @@ module Grape
|
|
404
419
|
options[:options_route_enabled] &&
|
405
420
|
env[Rack::REQUEST_METHOD] == Rack::OPTIONS
|
406
421
|
end
|
407
|
-
|
408
|
-
def inspect
|
409
|
-
"#{self.class} in `#{route.origin}' endpoint"
|
410
|
-
end
|
411
422
|
end
|
412
423
|
end
|
@@ -9,17 +9,18 @@ module Grape
|
|
9
9
|
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
|
10
10
|
result = wrap_message(present(message, env))
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
|
12
|
+
result = merge_rescue_options(result, backtrace, options, original_exception) if result.is_a?(Hash)
|
13
|
+
|
15
14
|
::Grape::Json.dump(result)
|
16
15
|
end
|
17
16
|
|
18
17
|
private
|
19
18
|
|
20
19
|
def wrap_message(message)
|
21
|
-
if message.is_a?(
|
20
|
+
if message.is_a?(Hash)
|
22
21
|
message
|
22
|
+
elsif message.is_a?(Exceptions::ValidationErrors)
|
23
|
+
message.as_json
|
23
24
|
else
|
24
25
|
{ error: ensure_utf8(message) }
|
25
26
|
end
|
@@ -30,6 +31,14 @@ module Grape
|
|
30
31
|
|
31
32
|
message.encode('UTF-8', invalid: :replace, undef: :replace)
|
32
33
|
end
|
34
|
+
|
35
|
+
def merge_rescue_options(result, backtrace, options, original_exception)
|
36
|
+
rescue_options = options[:rescue_options] || {}
|
37
|
+
result = result.merge(backtrace: backtrace) if rescue_options[:backtrace] && backtrace && !backtrace.empty?
|
38
|
+
result = result.merge(original_exception: original_exception.inspect) if rescue_options[:original_exception] && original_exception
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
33
42
|
end
|
34
43
|
end
|
35
44
|
end
|
@@ -2,34 +2,22 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ErrorFormatter
|
5
|
-
|
5
|
+
module_function
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
xml: Grape::ErrorFormatter::Xml
|
15
|
-
}
|
16
|
-
end
|
7
|
+
DEFAULTS = {
|
8
|
+
serializable_hash: Grape::ErrorFormatter::Json,
|
9
|
+
json: Grape::ErrorFormatter::Json,
|
10
|
+
jsonapi: Grape::ErrorFormatter::Json,
|
11
|
+
txt: Grape::ErrorFormatter::Txt,
|
12
|
+
xml: Grape::ErrorFormatter::Xml
|
13
|
+
}.freeze
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
def formatter_for(format, error_formatters = nil, default_error_formatter = nil)
|
16
|
+
select_formatter(error_formatters, format) || default_error_formatter || DEFAULTS[:txt]
|
17
|
+
end
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
case spec
|
25
|
-
when nil
|
26
|
-
options[:default_error_formatter] || Grape::ErrorFormatter::Txt
|
27
|
-
when Symbol
|
28
|
-
method(spec)
|
29
|
-
else
|
30
|
-
spec
|
31
|
-
end
|
32
|
-
end
|
19
|
+
def select_formatter(error_formatters, format)
|
20
|
+
error_formatters&.key?(format) ? error_formatters[format] : DEFAULTS[format]
|
33
21
|
end
|
34
22
|
end
|
35
23
|
end
|
data/lib/grape/formatter.rb
CHANGED
@@ -2,34 +2,24 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Formatter
|
5
|
-
|
5
|
+
module_function
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
xml: Grape::Formatter::Xml
|
15
|
-
}
|
16
|
-
end
|
7
|
+
DEFAULTS = {
|
8
|
+
json: Grape::Formatter::Json,
|
9
|
+
jsonapi: Grape::Formatter::Json,
|
10
|
+
serializable_hash: Grape::Formatter::SerializableHash,
|
11
|
+
txt: Grape::Formatter::Txt,
|
12
|
+
xml: Grape::Formatter::Xml
|
13
|
+
}.freeze
|
17
14
|
|
18
|
-
|
19
|
-
builtin_formatters.merge(default_elements).merge!(options[:formatters] || {})
|
20
|
-
end
|
15
|
+
DEFAULT_LAMBDA_FORMATTER = ->(obj, _env) { obj }
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
method(spec)
|
29
|
-
else
|
30
|
-
spec
|
31
|
-
end
|
32
|
-
end
|
17
|
+
def formatter_for(api_format, formatters)
|
18
|
+
select_formatter(formatters, api_format) || DEFAULT_LAMBDA_FORMATTER
|
19
|
+
end
|
20
|
+
|
21
|
+
def select_formatter(formatters, api_format)
|
22
|
+
formatters&.key?(api_format) ? formatters[api_format] : DEFAULTS[api_format]
|
33
23
|
end
|
34
24
|
end
|
35
25
|
end
|
data/lib/grape/locale/en.yml
CHANGED
@@ -11,6 +11,7 @@ en:
|
|
11
11
|
except_values: 'has a value not allowed'
|
12
12
|
same_as: 'is not the same as %{parameter}'
|
13
13
|
length: 'is expected to have length within %{min} and %{max}'
|
14
|
+
length_is: 'is expected to have length exactly equal to %{is}'
|
14
15
|
length_min: 'is expected to have length greater than or equal to %{min}'
|
15
16
|
length_max: 'is expected to have length less than or equal to %{max}'
|
16
17
|
missing_vendor_option:
|