grape 3.1.1 → 3.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 +21 -1
- data/README.md +76 -161
- data/UPGRADING.md +106 -0
- data/grape.gemspec +2 -2
- data/lib/grape/api/instance.rb +1 -1
- data/lib/grape/api.rb +1 -1
- data/lib/grape/declared_params_handler.rb +3 -3
- data/lib/grape/dsl/declared.rb +1 -1
- data/lib/grape/dsl/desc.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +9 -9
- data/lib/grape/dsl/parameters.rb +14 -14
- data/lib/grape/dsl/routing.rb +8 -8
- data/lib/grape/endpoint.rb +42 -49
- data/lib/grape/error_formatter/base.rb +2 -2
- data/lib/grape/exceptions/base.rb +18 -44
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_message_body.rb +1 -1
- data/lib/grape/exceptions/invalid_version_header.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/method_not_allowed.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/request_error.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +1 -1
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_params_builder.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/validation.rb +7 -4
- data/lib/grape/exceptions/validation_errors.rb +13 -7
- data/lib/grape/locale/en.yml +0 -5
- data/lib/grape/middleware/auth/base.rb +2 -0
- data/lib/grape/middleware/base.rb +2 -4
- data/lib/grape/middleware/error.rb +2 -2
- data/lib/grape/middleware/formatter.rb +1 -1
- data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
- data/lib/grape/request.rb +2 -10
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router.rb +4 -2
- data/lib/grape/util/api_description.rb +1 -1
- data/lib/grape/util/deep_freeze.rb +35 -0
- data/lib/grape/util/inheritable_setting.rb +1 -1
- data/lib/grape/util/media_type.rb +1 -1
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +33 -18
- data/lib/grape/validations/contract_scope.rb +1 -7
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/param_scope_tracker.rb +57 -0
- data/lib/grape/validations/params_scope.rb +111 -107
- data/lib/grape/validations/single_attribute_iterator.rb +2 -2
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
- data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
- data/lib/grape/validations/validators/base.rb +95 -18
- data/lib/grape/validations/validators/coerce_validator.rb +15 -35
- data/lib/grape/validations/validators/contract_scope_validator.rb +10 -8
- data/lib/grape/validations/validators/default_validator.rb +12 -18
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
- data/lib/grape/validations/validators/except_values_validator.rb +13 -4
- data/lib/grape/validations/validators/length_validator.rb +21 -22
- data/lib/grape/validations/validators/multiple_params_base.rb +5 -5
- data/lib/grape/validations/validators/mutually_exclusive_validator.rb +3 -1
- data/lib/grape/validations/validators/presence_validator.rb +4 -2
- data/lib/grape/validations/validators/regexp_validator.rb +8 -10
- data/lib/grape/validations/validators/same_as_validator.rb +6 -15
- data/lib/grape/validations/validators/values_validator.rb +29 -21
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +18 -1
- metadata +11 -13
- data/lib/grape/exceptions/conflicting_types.rb +0 -11
- data/lib/grape/exceptions/empty_message_body.rb +0 -11
- data/lib/grape/exceptions/invalid_parameters.rb +0 -11
- data/lib/grape/exceptions/too_deep_parameters.rb +0 -11
- data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
- data/lib/grape/validations/validator_factory.rb +0 -15
data/lib/grape/dsl/routing.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Grape
|
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
@versions
|
|
63
|
+
@versions&.last
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
# Define a root URL prefix for your entire API.
|
|
@@ -136,8 +136,8 @@ module Grape
|
|
|
136
136
|
endpoints << Grape::Endpoint.new(
|
|
137
137
|
in_setting,
|
|
138
138
|
method: :any,
|
|
139
|
-
path
|
|
140
|
-
app
|
|
139
|
+
path:,
|
|
140
|
+
app:,
|
|
141
141
|
route_options: { anchor: false },
|
|
142
142
|
forward_match: !app.respond_to?(:inheritable_setting),
|
|
143
143
|
for: self
|
|
@@ -167,13 +167,13 @@ module Grape
|
|
|
167
167
|
|
|
168
168
|
new_endpoint = Grape::Endpoint.new(
|
|
169
169
|
inheritable_setting,
|
|
170
|
-
method
|
|
170
|
+
method:,
|
|
171
171
|
path: paths,
|
|
172
172
|
for: self,
|
|
173
173
|
route_options: all_route_options,
|
|
174
174
|
&
|
|
175
175
|
)
|
|
176
|
-
endpoints << new_endpoint unless endpoints.
|
|
176
|
+
endpoints << new_endpoint unless endpoints.include?(new_endpoint)
|
|
177
177
|
|
|
178
178
|
inheritable_setting.route_end
|
|
179
179
|
reset_validations!
|
|
@@ -203,7 +203,7 @@ module Grape
|
|
|
203
203
|
|
|
204
204
|
within_namespace do
|
|
205
205
|
nest(block) do
|
|
206
|
-
inheritable_setting.namespace_stackable[:namespace] = Grape::Namespace.new(space, requirements
|
|
206
|
+
inheritable_setting.namespace_stackable[:namespace] = Grape::Namespace.new(space, requirements:, **options) if space
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
end
|
|
@@ -223,14 +223,14 @@ module Grape
|
|
|
223
223
|
#
|
|
224
224
|
# @param param [Symbol] The name of the parameter you wish to declare.
|
|
225
225
|
# @option options [Regexp] You may supply a regular expression that the declared parameter must meet.
|
|
226
|
-
def route_param(param, requirements: nil, type: nil,
|
|
226
|
+
def route_param(param, requirements: nil, type: nil, **, &)
|
|
227
227
|
requirements = { param.to_sym => requirements } if requirements.is_a?(Regexp)
|
|
228
228
|
|
|
229
229
|
Grape::Validations::ParamsScope.new(api: self) do
|
|
230
230
|
requires param, type: type
|
|
231
231
|
end if type
|
|
232
232
|
|
|
233
|
-
namespace(":#{param}", requirements
|
|
233
|
+
namespace(":#{param}", requirements:, **, &)
|
|
234
234
|
end
|
|
235
235
|
|
|
236
236
|
# @return array of defined versions
|
data/lib/grape/endpoint.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Grape
|
|
|
11
11
|
include Grape::DSL::Headers
|
|
12
12
|
include Grape::DSL::InsideRoute
|
|
13
13
|
|
|
14
|
-
attr_reader :env, :request, :source, :options
|
|
14
|
+
attr_reader :env, :request, :source, :options, :endpoints
|
|
15
15
|
|
|
16
16
|
def_delegators :request, :params, :headers, :cookies
|
|
17
17
|
def_delegator :cookies, :response_cookies
|
|
@@ -66,20 +66,21 @@ module Grape
|
|
|
66
66
|
inheritable_setting.route[:declared_params] = inheritable_setting.namespace_stackable[:declared_params].flatten
|
|
67
67
|
inheritable_setting.route[:saved_validations] = inheritable_setting.namespace_stackable[:validations]
|
|
68
68
|
|
|
69
|
-
inheritable_setting.namespace_stackable[:representations]
|
|
70
|
-
inheritable_setting.namespace_inheritable[:default_error_status]
|
|
69
|
+
inheritable_setting.namespace_stackable[:representations] ||= []
|
|
70
|
+
inheritable_setting.namespace_inheritable[:default_error_status] ||= 500
|
|
71
71
|
|
|
72
72
|
@options = options
|
|
73
73
|
|
|
74
|
-
@options[:path] = Array(options[:path])
|
|
75
|
-
@options[:path] << '/' if options[:path].empty?
|
|
76
|
-
@options[:method] = Array(options[:method])
|
|
74
|
+
@options[:path] = Array(@options[:path])
|
|
75
|
+
@options[:path] << '/' if @options[:path].empty?
|
|
76
|
+
@options[:method] = Array(@options[:method])
|
|
77
77
|
|
|
78
78
|
@status = nil
|
|
79
79
|
@stream = nil
|
|
80
80
|
@body = nil
|
|
81
81
|
@source = self.class.block_to_unbound_method(block)
|
|
82
82
|
@before_filter_passed = false
|
|
83
|
+
@endpoints = @options[:app].endpoints if @options[:app].respond_to?(:endpoints)
|
|
83
84
|
end
|
|
84
85
|
|
|
85
86
|
# Update our settings from a given set of stackable parameters. Used when
|
|
@@ -94,7 +95,7 @@ module Grape
|
|
|
94
95
|
end
|
|
95
96
|
|
|
96
97
|
def routes
|
|
97
|
-
@routes ||= endpoints&.
|
|
98
|
+
@routes ||= endpoints&.flat_map(&:routes) || to_routes
|
|
98
99
|
end
|
|
99
100
|
|
|
100
101
|
def reset_routes!
|
|
@@ -113,7 +114,7 @@ module Grape
|
|
|
113
114
|
compile!
|
|
114
115
|
routes.each do |route|
|
|
115
116
|
router.append(route.apply(self))
|
|
116
|
-
next
|
|
117
|
+
next if inheritable_setting.namespace_inheritable[:do_not_route_head] || route.request_method != Rack::GET
|
|
117
118
|
|
|
118
119
|
route.dup.then do |head_route|
|
|
119
120
|
head_route.convert_to_head_request!
|
|
@@ -138,15 +139,12 @@ module Grape
|
|
|
138
139
|
@app.call(env)
|
|
139
140
|
end
|
|
140
141
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def equals?(endpoint)
|
|
148
|
-
(options == endpoint.options) && (inheritable_setting.to_hash == endpoint.inheritable_setting.to_hash)
|
|
142
|
+
def ==(other)
|
|
143
|
+
other.is_a?(self.class) &&
|
|
144
|
+
options == other.options &&
|
|
145
|
+
inheritable_setting.to_hash == other.inheritable_setting.to_hash
|
|
149
146
|
end
|
|
147
|
+
alias eql? ==
|
|
150
148
|
|
|
151
149
|
# The purpose of this override is solely for stripping internals when an error occurs while calling
|
|
152
150
|
# an endpoint through an api. See https://github.com/ruby-grape/grape/issues/2398
|
|
@@ -160,7 +158,7 @@ module Grape
|
|
|
160
158
|
protected
|
|
161
159
|
|
|
162
160
|
def run
|
|
163
|
-
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env:
|
|
161
|
+
ActiveSupport::Notifications.instrument('endpoint_run.grape', endpoint: self, env:) do
|
|
164
162
|
@request = Grape::Request.new(env, build_params_with: inheritable_setting.namespace_inheritable[:build_params_with])
|
|
165
163
|
begin
|
|
166
164
|
self.class.run_before_each(self)
|
|
@@ -176,7 +174,7 @@ module Grape
|
|
|
176
174
|
status 204
|
|
177
175
|
else
|
|
178
176
|
run_filters before_validations, :before_validation
|
|
179
|
-
run_validators
|
|
177
|
+
run_validators(request:)
|
|
180
178
|
run_filters after_validations, :after_validation
|
|
181
179
|
response_object = execute
|
|
182
180
|
end
|
|
@@ -198,35 +196,40 @@ module Grape
|
|
|
198
196
|
end
|
|
199
197
|
|
|
200
198
|
def execute
|
|
201
|
-
return unless
|
|
199
|
+
return unless source
|
|
202
200
|
|
|
203
201
|
ActiveSupport::Notifications.instrument('endpoint_render.grape', endpoint: self) do
|
|
204
|
-
|
|
202
|
+
source.bind_call(self)
|
|
205
203
|
end
|
|
206
204
|
end
|
|
207
205
|
|
|
208
|
-
def run_validators(
|
|
206
|
+
def run_validators(request:)
|
|
207
|
+
validators = inheritable_setting.route[:saved_validations]
|
|
208
|
+
return if validators.empty?
|
|
209
|
+
|
|
209
210
|
validation_errors = []
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
validator
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
212
|
+
Grape::Validations::ParamScopeTracker.track do
|
|
213
|
+
ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators:, request:) do
|
|
214
|
+
validators.each do |validator|
|
|
215
|
+
validator.validate(request)
|
|
216
|
+
rescue Grape::Exceptions::Validation => e
|
|
217
|
+
validation_errors << e
|
|
218
|
+
break if validator.fail_fast?
|
|
219
|
+
rescue Grape::Exceptions::ValidationArrayErrors => e
|
|
220
|
+
validation_errors.concat e.errors
|
|
221
|
+
break if validator.fail_fast?
|
|
222
|
+
end
|
|
220
223
|
end
|
|
221
224
|
end
|
|
222
225
|
|
|
223
|
-
|
|
226
|
+
raise(Grape::Exceptions::ValidationErrors.new(errors: validation_errors, headers: header)) if validation_errors.any?
|
|
224
227
|
end
|
|
225
228
|
|
|
226
229
|
def run_filters(filters, type = :other)
|
|
227
230
|
return unless filters
|
|
228
231
|
|
|
229
|
-
ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters
|
|
232
|
+
ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters:, type:) do
|
|
230
233
|
filters.each { |filter| instance_eval(&filter) }
|
|
231
234
|
end
|
|
232
235
|
end
|
|
@@ -237,16 +240,6 @@ module Grape
|
|
|
237
240
|
end
|
|
238
241
|
end
|
|
239
242
|
|
|
240
|
-
def validations
|
|
241
|
-
saved_validations = inheritable_setting.route[:saved_validations]
|
|
242
|
-
return if saved_validations.nil?
|
|
243
|
-
return enum_for(:validations) unless block_given?
|
|
244
|
-
|
|
245
|
-
saved_validations.each do |saved_validation|
|
|
246
|
-
yield Grape::Validations::ValidatorFactory.create_validator(saved_validation)
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
243
|
def options?
|
|
251
244
|
options[:options_route_enabled] &&
|
|
252
245
|
env[Rack::REQUEST_METHOD] == Rack::OPTIONS
|
|
@@ -286,7 +279,7 @@ module Grape
|
|
|
286
279
|
|
|
287
280
|
def prepare_default_route_attributes(route_options)
|
|
288
281
|
{
|
|
289
|
-
namespace
|
|
282
|
+
namespace:,
|
|
290
283
|
version: prepare_version(inheritable_setting.namespace_inheritable[:version]),
|
|
291
284
|
requirements: prepare_routes_requirements(route_options[:requirements]),
|
|
292
285
|
prefix: inheritable_setting.namespace_inheritable[:root_prefix],
|
|
@@ -323,15 +316,15 @@ module Grape
|
|
|
323
316
|
stack.use Rack::Head
|
|
324
317
|
stack.use Rack::Lint if lint?
|
|
325
318
|
stack.use Grape::Middleware::Error,
|
|
326
|
-
format
|
|
327
|
-
content_types
|
|
319
|
+
format:,
|
|
320
|
+
content_types:,
|
|
328
321
|
default_status: inheritable_setting.namespace_inheritable[:default_error_status],
|
|
329
322
|
rescue_all: inheritable_setting.namespace_inheritable[:rescue_all],
|
|
330
323
|
rescue_grape_exceptions: inheritable_setting.namespace_inheritable[:rescue_grape_exceptions],
|
|
331
324
|
default_error_formatter: inheritable_setting.namespace_inheritable[:default_error_formatter],
|
|
332
325
|
error_formatters: inheritable_setting.namespace_stackable_with_hash(:error_formatters),
|
|
333
326
|
rescue_options: inheritable_setting.namespace_stackable_with_hash(:rescue_options),
|
|
334
|
-
rescue_handlers
|
|
327
|
+
rescue_handlers:,
|
|
335
328
|
base_only_rescue_handlers: inheritable_setting.namespace_stackable_with_hash(:base_only_rescue_handlers),
|
|
336
329
|
all_rescue_handler: inheritable_setting.namespace_inheritable[:all_rescue_handler],
|
|
337
330
|
grape_exceptions_rescue_handler: inheritable_setting.namespace_inheritable[:grape_exceptions_rescue_handler]
|
|
@@ -347,9 +340,9 @@ module Grape
|
|
|
347
340
|
end
|
|
348
341
|
|
|
349
342
|
stack.use Grape::Middleware::Formatter,
|
|
350
|
-
format
|
|
343
|
+
format:,
|
|
351
344
|
default_format: inheritable_setting.namespace_inheritable[:default_format] || :txt,
|
|
352
|
-
content_types
|
|
345
|
+
content_types:,
|
|
353
346
|
formatters: inheritable_setting.namespace_stackable_with_hash(:formatters),
|
|
354
347
|
parsers: inheritable_setting.namespace_stackable_with_hash(:parsers)
|
|
355
348
|
|
|
@@ -367,7 +360,7 @@ module Grape
|
|
|
367
360
|
|
|
368
361
|
def build_response_cookies
|
|
369
362
|
response_cookies do |name, value|
|
|
370
|
-
cookie_value = value.is_a?(Hash) ? value : { value:
|
|
363
|
+
cookie_value = value.is_a?(Hash) ? value : { value: }
|
|
371
364
|
Rack::Utils.set_cookie_header! header, name, cookie_value
|
|
372
365
|
end
|
|
373
366
|
end
|
|
@@ -40,7 +40,7 @@ module Grape
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
if presenter
|
|
43
|
-
embeds = { env:
|
|
43
|
+
embeds = { env: }
|
|
44
44
|
embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
|
|
45
45
|
presented_message = presenter.represent(presented_message, embeds).serializable_hash
|
|
46
46
|
end
|
|
@@ -51,7 +51,7 @@ module Grape
|
|
|
51
51
|
def wrap_message(message)
|
|
52
52
|
return message if message.is_a?(Hash)
|
|
53
53
|
|
|
54
|
-
{ message:
|
|
54
|
+
{ message: }
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def format_structured_message(_structured_message)
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class Base < StandardError
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
include Grape::Util::Translation
|
|
7
|
+
|
|
8
|
+
MESSAGE_STEPS = %w[problem summary resolution].to_h { |s| [s, s.capitalize] }.freeze
|
|
9
9
|
|
|
10
10
|
attr_reader :status, :headers
|
|
11
11
|
|
|
@@ -20,55 +20,29 @@ module Grape
|
|
|
20
20
|
__send__ index
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
private
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
|
|
28
|
-
def compose_message(key, **attributes)
|
|
29
|
-
short_message = translate_message(key, attributes)
|
|
25
|
+
def compose_message(key, **)
|
|
26
|
+
short_message = translate_message(key, **)
|
|
30
27
|
return short_message unless short_message.is_a?(Hash)
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def each_steps(key, attributes)
|
|
38
|
-
return enum_for(:each_steps, key, attributes) unless block_given?
|
|
39
|
-
|
|
40
|
-
yield 'Problem', translate_message(:"#{key}.problem", attributes)
|
|
41
|
-
yield 'Summary', translate_message(:"#{key}.summary", attributes)
|
|
42
|
-
yield 'Resolution', translate_message(:"#{key}.resolution", attributes)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def translate_attributes(keys, options = {})
|
|
46
|
-
keys.map do |key|
|
|
47
|
-
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", options.merge(default: key.to_s))
|
|
48
|
-
end.join(', ')
|
|
29
|
+
MESSAGE_STEPS.filter_map do |step, label|
|
|
30
|
+
detail = translate_message(:"#{key}.#{step}", **)
|
|
31
|
+
"\n#{label}:\n #{detail}" if detail.present?
|
|
32
|
+
end.join
|
|
49
33
|
end
|
|
50
34
|
|
|
51
|
-
def translate_message(
|
|
52
|
-
case
|
|
35
|
+
def translate_message(translation_key, **)
|
|
36
|
+
case translation_key
|
|
53
37
|
when Symbol
|
|
54
|
-
translate(
|
|
38
|
+
translate(translation_key, **)
|
|
39
|
+
when Hash
|
|
40
|
+
translation_key => { key:, **opts }
|
|
41
|
+
translate(key, **opts)
|
|
55
42
|
when Proc
|
|
56
|
-
|
|
57
|
-
else
|
|
58
|
-
key
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def translate(key, options)
|
|
63
|
-
message = ::I18n.translate(key, **options)
|
|
64
|
-
message.presence || fallback_message(key, options)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def fallback_message(key, options)
|
|
68
|
-
if ::I18n.enforce_available_locales && !::I18n.available_locales.include?(FALLBACK_LOCALE)
|
|
69
|
-
key
|
|
43
|
+
translation_key.call
|
|
70
44
|
else
|
|
71
|
-
|
|
45
|
+
translation_key
|
|
72
46
|
end
|
|
73
47
|
end
|
|
74
48
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class IncompatibleOptionValues < Base
|
|
6
6
|
def initialize(option1, value1, option2, value2)
|
|
7
|
-
super(message: compose_message(:incompatible_option_values, option1
|
|
7
|
+
super(message: compose_message(:incompatible_option_values, option1:, value1:, option2:, value2:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidAcceptHeader < Base
|
|
6
6
|
def initialize(message, headers)
|
|
7
|
-
super(message: compose_message(:invalid_accept_header, message:
|
|
7
|
+
super(message: compose_message(:invalid_accept_header, message:), status: 406, headers:)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidFormatter < Base
|
|
6
6
|
def initialize(klass, to_format)
|
|
7
|
-
super(message: compose_message(:invalid_formatter, klass
|
|
7
|
+
super(message: compose_message(:invalid_formatter, klass:, to_format:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidMessageBody < Base
|
|
6
6
|
def initialize(body_format)
|
|
7
|
-
super(message: compose_message(:invalid_message_body, body_format:
|
|
7
|
+
super(message: compose_message(:invalid_message_body, body_format:), status: 400)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidVersionHeader < Base
|
|
6
6
|
def initialize(message, headers)
|
|
7
|
-
super(message: compose_message(:invalid_version_header, message:
|
|
7
|
+
super(message: compose_message(:invalid_version_header, message:), status: 406, headers:)
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class InvalidVersionerOption < Base
|
|
6
6
|
def initialize(strategy)
|
|
7
|
-
super(message: compose_message(:invalid_versioner_option, strategy:
|
|
7
|
+
super(message: compose_message(:invalid_versioner_option, strategy:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class UnknownParamsBuilder < Base
|
|
6
6
|
def initialize(params_builder_type)
|
|
7
|
-
super(message: compose_message(:unknown_params_builder, params_builder_type:
|
|
7
|
+
super(message: compose_message(:unknown_params_builder, params_builder_type:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -4,7 +4,7 @@ module Grape
|
|
|
4
4
|
module Exceptions
|
|
5
5
|
class UnknownValidator < Base
|
|
6
6
|
def initialize(validator_type)
|
|
7
|
-
super(message: compose_message(:unknown_validator, validator_type:
|
|
7
|
+
super(message: compose_message(:unknown_validator, validator_type:))
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
end
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class Validation < Base
|
|
6
|
-
|
|
6
|
+
attr_reader :params, :message_key
|
|
7
7
|
|
|
8
8
|
def initialize(params:, message: nil, status: nil, headers: nil)
|
|
9
|
-
@params = params
|
|
9
|
+
@params = Array(params)
|
|
10
10
|
if message
|
|
11
|
-
@message_key =
|
|
11
|
+
@message_key = case message
|
|
12
|
+
when Symbol then message
|
|
13
|
+
when Hash then message[:key]
|
|
14
|
+
end
|
|
12
15
|
message = translate_message(message)
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
super(status
|
|
18
|
+
super(status:, message:, headers:)
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
# Remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
|
@@ -3,16 +3,13 @@
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Exceptions
|
|
5
5
|
class ValidationErrors < Base
|
|
6
|
-
ERRORS_FORMAT_KEY = 'grape.errors.format'
|
|
7
|
-
DEFAULT_ERRORS_FORMAT = '%<attributes>s %<message>s'
|
|
8
|
-
|
|
9
6
|
include Enumerable
|
|
10
7
|
|
|
11
8
|
attr_reader :errors
|
|
12
9
|
|
|
13
10
|
def initialize(errors: [], headers: {})
|
|
14
11
|
@errors = errors.group_by(&:params)
|
|
15
|
-
super(message: full_messages.join(', '), status: 400, headers:
|
|
12
|
+
super(message: full_messages.join(', '), status: 400, headers:)
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def each
|
|
@@ -38,9 +35,10 @@ module Grape
|
|
|
38
35
|
|
|
39
36
|
def full_messages
|
|
40
37
|
messages = map do |attributes, error|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
translate(
|
|
39
|
+
:format,
|
|
40
|
+
scope: 'grape.errors',
|
|
41
|
+
default: '%<attributes>s %<message>s',
|
|
44
42
|
attributes: translate_attributes(attributes),
|
|
45
43
|
message: error.message
|
|
46
44
|
)
|
|
@@ -48,6 +46,14 @@ module Grape
|
|
|
48
46
|
messages.uniq!
|
|
49
47
|
messages
|
|
50
48
|
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def translate_attributes(keys)
|
|
53
|
+
keys.map do |key|
|
|
54
|
+
translate(key, scope: 'grape.errors.attributes', default: key.to_s)
|
|
55
|
+
end.join(', ')
|
|
56
|
+
end
|
|
51
57
|
end
|
|
52
58
|
end
|
|
53
59
|
end
|
data/lib/grape/locale/en.yml
CHANGED
|
@@ -8,8 +8,6 @@ en:
|
|
|
8
8
|
at_least_one: 'are missing, at least one parameter must be provided'
|
|
9
9
|
blank: 'is empty'
|
|
10
10
|
coerce: 'is invalid'
|
|
11
|
-
conflicting_types: 'query params contains conflicting types'
|
|
12
|
-
empty_message_body: 'empty message body supplied with %{body_format} content-type'
|
|
13
11
|
exactly_one: 'are missing, exactly one parameter must be provided'
|
|
14
12
|
except_values: 'has a value not allowed'
|
|
15
13
|
incompatible_option_values: '%{option1}: %{value1} is incompatible with %{option2}: %{value2}'
|
|
@@ -20,7 +18,6 @@ en:
|
|
|
20
18
|
invalid_message_body:
|
|
21
19
|
problem: 'message body does not match declared format'
|
|
22
20
|
resolution: 'when specifying %{body_format} as content-type, you must pass valid %{body_format} in the request''s ''body'' '
|
|
23
|
-
invalid_parameters: 'query params contains invalid format or byte sequence'
|
|
24
21
|
invalid_response: 'Invalid response'
|
|
25
22
|
invalid_version_header:
|
|
26
23
|
problem: 'invalid version header'
|
|
@@ -48,8 +45,6 @@ en:
|
|
|
48
45
|
presence: 'is missing'
|
|
49
46
|
regexp: 'is invalid'
|
|
50
47
|
same_as: 'is not the same as %{parameter}'
|
|
51
|
-
too_deep_parameters: 'query params are recursively nested over the specified limit (%{limit})'
|
|
52
|
-
too_many_multipart_files: 'the number of uploaded files exceeded the system''s configured limit (%{limit})'
|
|
53
48
|
unknown_auth_strategy: 'unknown auth strategy: %{strategy}'
|
|
54
49
|
unknown_options: 'unknown options: %{options}'
|
|
55
50
|
unknown_parameter: 'unknown parameter: %{param}'
|
|
@@ -6,6 +6,8 @@ module Grape
|
|
|
6
6
|
class Base < Grape::Middleware::Base
|
|
7
7
|
def initialize(app, **options)
|
|
8
8
|
super
|
|
9
|
+
return unless options.key?(:type)
|
|
10
|
+
|
|
9
11
|
@auth_strategy = Grape::Middleware::Auth::Strategies[options[:type]].tap do |auth_strategy|
|
|
10
12
|
raise Grape::Exceptions::UnknownAuthStrategy.new(strategy: options[:type]) unless auth_strategy
|
|
11
13
|
end
|
|
@@ -79,10 +79,8 @@ module Grape
|
|
|
79
79
|
|
|
80
80
|
def query_params
|
|
81
81
|
rack_request.GET
|
|
82
|
-
rescue
|
|
83
|
-
raise Grape::Exceptions::
|
|
84
|
-
rescue Rack::Utils::ParameterTypeError
|
|
85
|
-
raise Grape::Exceptions::ConflictingTypes
|
|
82
|
+
rescue *Grape::RACK_ERRORS
|
|
83
|
+
raise Grape::Exceptions::RequestError
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
private
|
|
@@ -38,7 +38,7 @@ module Grape
|
|
|
38
38
|
else
|
|
39
39
|
# Allow content-type to be explicitly overwritten
|
|
40
40
|
formatter = fetch_formatter(headers, options)
|
|
41
|
-
bodymap = ActiveSupport::Notifications.instrument('format_response.grape', formatter
|
|
41
|
+
bodymap = ActiveSupport::Notifications.instrument('format_response.grape', formatter:, env:) do
|
|
42
42
|
bodies.collect { |body| formatter.call(body, env) }
|
|
43
43
|
end
|
|
44
44
|
Rack::Response.new(bodymap, status, headers)
|