grape 1.0.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +346 -39
- data/LICENSE +1 -1
- data/README.md +658 -90
- data/UPGRADING.md +472 -17
- data/grape.gemspec +17 -6
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +279 -0
- data/lib/grape/api.rb +132 -176
- data/lib/grape/config.rb +34 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +4 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +22 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +44 -12
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +11 -6
- data/lib/grape/dsl/inside_route.rb +116 -36
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +12 -3
- data/lib/grape/dsl/parameters.rb +34 -16
- data/lib/grape/dsl/request_response.rb +13 -8
- data/lib/grape/dsl/routing.rb +19 -12
- data/lib/grape/dsl/settings.rb +22 -4
- data/lib/grape/dsl/validations.rb +24 -4
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +66 -57
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +6 -4
- data/lib/grape/error_formatter/txt.rb +10 -3
- data/lib/grape/error_formatter/xml.rb +6 -4
- data/lib/grape/error_formatter.rb +4 -2
- data/lib/grape/exceptions/base.rb +22 -14
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -1
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -1
- data/lib/grape/exceptions/invalid_formatter.rb +2 -1
- data/lib/grape/exceptions/invalid_message_body.rb +2 -1
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -1
- data/lib/grape/exceptions/method_not_allowed.rb +2 -1
- data/lib/grape/exceptions/missing_group_type.rb +2 -1
- data/lib/grape/exceptions/missing_mime_type.rb +2 -1
- data/lib/grape/exceptions/missing_option.rb +2 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -1
- data/lib/grape/exceptions/unknown_options.rb +2 -1
- data/lib/grape/exceptions/unknown_parameter.rb +2 -1
- data/lib/grape/exceptions/unknown_validator.rb +2 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -1
- data/lib/grape/exceptions/validation.rb +5 -4
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +16 -13
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter/json.rb +3 -0
- data/lib/grape/formatter/serializable_hash.rb +4 -1
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +3 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/locale/en.yml +3 -1
- data/lib/grape/middleware/auth/base.rb +7 -7
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +12 -7
- data/lib/grape/middleware/error.rb +75 -61
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +17 -13
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +12 -0
- data/lib/grape/middleware/stack.rb +15 -5
- data/lib/grape/middleware/versioner/accept_version_header.rb +5 -5
- data/lib/grape/middleware/versioner/header.rb +13 -9
- data/lib/grape/middleware/versioner/param.rb +4 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +5 -1
- data/lib/grape/middleware/versioner/path.rb +5 -1
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/namespace.rb +15 -3
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/parser.rb +4 -2
- data/lib/grape/path.rb +16 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +19 -9
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +22 -18
- data/lib/grape/router/route.rb +16 -30
- data/lib/grape/router.rb +37 -28
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +3 -3
- data/lib/grape/util/inheritable_values.rb +7 -25
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +27 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +99 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +10 -35
- data/lib/grape/util/stackable_values.rb +21 -34
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +16 -6
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +128 -66
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +52 -46
- data/lib/grape/validations/types/custom_type_coercer.rb +30 -51
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +47 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/types.rb +26 -38
- data/lib/grape/validations/validator_factory.rb +8 -11
- data/lib/grape/validations/validators/all_or_none.rb +8 -12
- data/lib/grape/validations/validators/allow_blank.rb +4 -2
- data/lib/grape/validations/validators/as.rb +12 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -12
- data/lib/grape/validations/validators/base.rb +23 -15
- data/lib/grape/validations/validators/coerce.rb +47 -28
- data/lib/grape/validations/validators/default.rb +7 -6
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -22
- data/lib/grape/validations/validators/except_values.rb +4 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +19 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -17
- data/lib/grape/validations/validators/presence.rb +4 -1
- data/lib/grape/validations/validators/regexp.rb +5 -2
- data/lib/grape/validations/validators/same_as.rb +27 -0
- data/lib/grape/validations/validators/values.rb +29 -9
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/version.rb +3 -1
- data/lib/grape.rb +107 -73
- data/spec/grape/api/custom_validations_spec.rb +6 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
- data/spec/grape/api/inherited_helpers_spec.rb +116 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +49 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +473 -0
- data/spec/grape/api_spec.rb +775 -65
- data/spec/grape/config_spec.rb +19 -0
- data/spec/grape/dsl/callbacks_spec.rb +3 -1
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +42 -16
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +23 -2
- data/spec/grape/dsl/inside_route_spec.rb +185 -34
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +11 -1
- data/spec/grape/dsl/parameters_spec.rb +12 -9
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +13 -1
- data/spec/grape/dsl/settings_spec.rb +4 -2
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint/declared_spec.rb +848 -0
- data/spec/grape/endpoint_spec.rb +75 -515
- data/spec/grape/entity_spec.rb +19 -11
- data/spec/grape/exceptions/base_spec.rb +67 -0
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -1
- data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -1
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -1
- data/spec/grape/exceptions/unknown_options_spec.rb +3 -2
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -1
- data/spec/grape/exceptions/validation_errors_spec.rb +17 -4
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +25 -7
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +6 -4
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +10 -0
- data/spec/grape/middleware/error_spec.rb +4 -3
- data/spec/grape/middleware/exception_spec.rb +205 -55
- data/spec/grape/middleware/formatter_spec.rb +130 -15
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +15 -1
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +10 -2
- data/spec/grape/middleware/versioner/param_spec.rb +4 -2
- data/spec/grape/middleware/versioner/path_spec.rb +4 -2
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +21 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +9 -7
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +26 -0
- data/spec/grape/util/inheritable_setting_spec.rb +4 -2
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +15 -13
- data/spec/grape/util/stackable_values_spec.rb +16 -14
- data/spec/grape/util/strict_hash_configuration_spec.rb +3 -1
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
- data/spec/grape/validations/params_scope_spec.rb +364 -7
- data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
- data/spec/grape/validations/validators/coerce_spec.rb +558 -133
- data/spec/grape/validations/validators/default_spec.rb +212 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
- data/spec/grape/validations/validators/except_values_spec.rb +6 -3
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +65 -0
- data/spec/grape/validations/validators/values_spec.rb +73 -19
- data/spec/grape/validations_spec.rb +403 -53
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +78 -18
- data/spec/spec_helper.rb +13 -2
- data/spec/support/basic_auth_encode_helpers.rb +3 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/content_type_helpers.rb +3 -1
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +8 -8
- metadata +176 -130
- data/Appraisals +0 -32
- data/Dangerfile +0 -1
- data/Gemfile +0 -34
- data/Gemfile.lock +0 -229
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -70
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -36
- data/gemfiles/multi_xml.gemfile +0 -36
- data/gemfiles/rack_1.5.2.gemfile +0 -36
- data/gemfiles/rack_edge.gemfile +0 -36
- data/gemfiles/rails_3.gemfile +0 -37
- data/gemfiles/rails_4.gemfile +0 -36
- data/gemfiles/rails_5.gemfile +0 -36
- data/gemfiles/rails_edge.gemfile +0 -36
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -70,7 +72,7 @@ module Grape
|
|
70
72
|
|
71
73
|
# Require one or more parameters for the current endpoint.
|
72
74
|
#
|
73
|
-
# @param attrs list of
|
75
|
+
# @param attrs list of parameters names, or, if :using is
|
74
76
|
# passed as an option, which keys to include (:all or :none) from
|
75
77
|
# the :using hash. The last key can be a hash, which specifies
|
76
78
|
# options for the parameters
|
@@ -125,14 +127,13 @@ module Grape
|
|
125
127
|
|
126
128
|
opts = attrs.extract_options!.clone
|
127
129
|
opts[:presence] = { value: true, message: opts[:message] }
|
128
|
-
opts = @group.merge(opts) if @group
|
130
|
+
opts = @group.merge(opts) if instance_variable_defined?(:@group) && @group
|
129
131
|
|
130
132
|
if opts[:using]
|
131
133
|
require_required_and_optional_fields(attrs.first, opts)
|
132
134
|
else
|
133
135
|
validate_attributes(attrs, opts, &block)
|
134
|
-
|
135
|
-
block_given? ? new_scope(orig_attrs, &block) : push_declared_params(attrs)
|
136
|
+
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, **opts.slice(:as))
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
@@ -145,10 +146,10 @@ module Grape
|
|
145
146
|
|
146
147
|
opts = attrs.extract_options!.clone
|
147
148
|
type = opts[:type]
|
148
|
-
opts = @group.merge(opts) if @group
|
149
|
+
opts = @group.merge(opts) if instance_variable_defined?(:@group) && @group
|
149
150
|
|
150
151
|
# check type for optional parameter group
|
151
|
-
if attrs &&
|
152
|
+
if attrs && block
|
152
153
|
raise Grape::Exceptions::MissingGroupTypeError.new if type.nil?
|
153
154
|
raise Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
|
154
155
|
end
|
@@ -158,7 +159,7 @@ module Grape
|
|
158
159
|
else
|
159
160
|
validate_attributes(attrs, opts, &block)
|
160
161
|
|
161
|
-
|
162
|
+
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, **opts.slice(:as))
|
162
163
|
end
|
163
164
|
end
|
164
165
|
|
@@ -202,7 +203,7 @@ module Grape
|
|
202
203
|
# @yield a parameter definition DSL
|
203
204
|
def given(*attrs, &block)
|
204
205
|
attrs.each do |attr|
|
205
|
-
proxy_attr = attr
|
206
|
+
proxy_attr = first_hash_key_or_param(attr)
|
206
207
|
raise Grape::Exceptions::UnknownParameter.new(proxy_attr) unless declared_param?(proxy_attr)
|
207
208
|
end
|
208
209
|
new_lateral_scope(dependent_on: attrs, &block)
|
@@ -212,20 +213,31 @@ module Grape
|
|
212
213
|
# block yet.
|
213
214
|
# @return [Boolean] whether the parameter has been defined
|
214
215
|
def declared_param?(param)
|
215
|
-
|
216
|
-
|
217
|
-
|
216
|
+
if lateral?
|
217
|
+
# Elements of @declared_params of lateral scope are pushed in @parent. So check them in @parent.
|
218
|
+
@parent.declared_param?(param)
|
219
|
+
else
|
220
|
+
# @declared_params also includes hashes of options and such, but those
|
221
|
+
# won't be flattened out.
|
222
|
+
@declared_params.flatten.any? do |declared_param|
|
223
|
+
first_hash_key_or_param(declared_param) == param
|
224
|
+
end
|
225
|
+
end
|
218
226
|
end
|
219
227
|
|
220
228
|
alias group requires
|
221
229
|
|
222
|
-
|
230
|
+
class EmptyOptionalValue; end
|
231
|
+
|
232
|
+
def map_params(params, element, is_array = false)
|
223
233
|
if params.is_a?(Array)
|
224
234
|
params.map do |el|
|
225
|
-
map_params(el, element)
|
235
|
+
map_params(el, element, true)
|
226
236
|
end
|
227
237
|
elsif params.is_a?(Hash)
|
228
|
-
params[element] || {}
|
238
|
+
params[element] || (@optional && is_array ? EmptyOptionalValue : {})
|
239
|
+
elsif params == EmptyOptionalValue
|
240
|
+
EmptyOptionalValue
|
229
241
|
else
|
230
242
|
{}
|
231
243
|
end
|
@@ -235,10 +247,16 @@ module Grape
|
|
235
247
|
# @return hash of parameters relevant for the current scope
|
236
248
|
# @api private
|
237
249
|
def params(params)
|
238
|
-
params = @parent.params(params) if @parent
|
239
|
-
params = map_params(params, @element) if @element
|
250
|
+
params = @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
251
|
+
params = map_params(params, @element) if instance_variable_defined?(:@element) && @element
|
240
252
|
params
|
241
253
|
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def first_hash_key_or_param(parameter)
|
258
|
+
parameter.is_a?(Hash) ? parameter.keys.first : parameter
|
259
|
+
end
|
242
260
|
end
|
243
261
|
end
|
244
262
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -20,10 +22,11 @@ module Grape
|
|
20
22
|
if new_format
|
21
23
|
namespace_inheritable(:format, new_format.to_sym)
|
22
24
|
# define the default error formatters
|
23
|
-
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(new_format, {}))
|
25
|
+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(new_format, **{}))
|
24
26
|
# define a single mime type
|
25
27
|
mime_type = content_types[new_format.to_sym]
|
26
28
|
raise Grape::Exceptions::MissingMimeType.new(new_format) unless mime_type
|
29
|
+
|
27
30
|
namespace_stackable(:content_types, new_format.to_sym => mime_type)
|
28
31
|
else
|
29
32
|
namespace_inheritable(:format)
|
@@ -43,7 +46,7 @@ module Grape
|
|
43
46
|
# Specify a default error formatter.
|
44
47
|
def default_error_formatter(new_formatter_name = nil)
|
45
48
|
if new_formatter_name
|
46
|
-
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name, {})
|
49
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name, **{})
|
47
50
|
namespace_inheritable(:default_error_formatter, new_formatter)
|
48
51
|
else
|
49
52
|
namespace_inheritable(:default_error_formatter)
|
@@ -100,14 +103,13 @@ module Grape
|
|
100
103
|
def rescue_from(*args, &block)
|
101
104
|
if args.last.is_a?(Proc)
|
102
105
|
handler = args.pop
|
103
|
-
elsif
|
106
|
+
elsif block
|
104
107
|
handler = block
|
105
108
|
end
|
106
109
|
|
107
110
|
options = args.extract_options!
|
108
|
-
if
|
109
|
-
|
110
|
-
end
|
111
|
+
raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
|
112
|
+
|
111
113
|
handler ||= extract_with(options)
|
112
114
|
|
113
115
|
if args.include?(:all)
|
@@ -125,7 +127,7 @@ module Grape
|
|
125
127
|
:base_only_rescue_handlers
|
126
128
|
end
|
127
129
|
|
128
|
-
namespace_reverse_stackable handler_type,
|
130
|
+
namespace_reverse_stackable handler_type, args.map { |arg| [arg, handler] }.to_h
|
129
131
|
end
|
130
132
|
|
131
133
|
namespace_stackable(:rescue_options, options)
|
@@ -152,7 +154,8 @@ module Grape
|
|
152
154
|
# @param model_class [Class] The model class that will be represented.
|
153
155
|
# @option options [Class] :with The entity class that will represent the model.
|
154
156
|
def represent(model_class, options)
|
155
|
-
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with]
|
157
|
+
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
|
158
|
+
|
156
159
|
namespace_stackable(:representations, model_class => options[:with])
|
157
160
|
end
|
158
161
|
|
@@ -160,9 +163,11 @@ module Grape
|
|
160
163
|
|
161
164
|
def extract_with(options)
|
162
165
|
return unless options.key?(:with)
|
166
|
+
|
163
167
|
with_option = options.delete(:with)
|
164
168
|
return with_option if with_option.instance_of?(Proc)
|
165
169
|
return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
|
170
|
+
|
166
171
|
raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
|
167
172
|
end
|
168
173
|
end
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -36,7 +38,7 @@ module Grape
|
|
36
38
|
|
37
39
|
@versions = versions | requested_versions
|
38
40
|
|
39
|
-
if
|
41
|
+
if block
|
40
42
|
within_namespace do
|
41
43
|
namespace_inheritable(:version, requested_versions)
|
42
44
|
namespace_inheritable(:version_options, options)
|
@@ -49,7 +51,7 @@ module Grape
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
@versions.last
|
54
|
+
@versions.last if instance_variable_defined?(:@versions) && @versions
|
53
55
|
end
|
54
56
|
|
55
57
|
# Define a root URL prefix for your entire API.
|
@@ -77,9 +79,14 @@ module Grape
|
|
77
79
|
namespace_inheritable(:do_not_route_options, true)
|
78
80
|
end
|
79
81
|
|
80
|
-
def mount(mounts)
|
82
|
+
def mount(mounts, *opts)
|
81
83
|
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
|
82
84
|
mounts.each_pair do |app, path|
|
85
|
+
if app.respond_to?(:mount_instance)
|
86
|
+
opts_with = opts.any? ? opts.shift[:with] : {}
|
87
|
+
mount({ app.mount_instance(configuration: opts_with) => path })
|
88
|
+
next
|
89
|
+
end
|
83
90
|
in_setting = inheritable_setting
|
84
91
|
|
85
92
|
if app.respond_to?(:inheritable_setting, true)
|
@@ -136,16 +143,16 @@ module Grape
|
|
136
143
|
reset_validations!
|
137
144
|
end
|
138
145
|
|
139
|
-
|
140
|
-
define_method
|
146
|
+
Grape::Http::Headers::SUPPORTED_METHODS.each do |supported_method|
|
147
|
+
define_method supported_method.downcase do |*args, &block|
|
141
148
|
options = args.extract_options!
|
142
149
|
paths = args.first || ['/']
|
143
|
-
route(
|
150
|
+
route(supported_method, paths, options, &block)
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
154
|
# Declare a "namespace", which prefixes all subordinate routes with its
|
148
|
-
# name. Any endpoints within a namespace,
|
155
|
+
# name. Any endpoints within a namespace, group, resource or segment,
|
149
156
|
# etc., will share their parent context as well as any configuration
|
150
157
|
# done in the namespace context.
|
151
158
|
#
|
@@ -157,14 +164,14 @@ module Grape
|
|
157
164
|
# end
|
158
165
|
# end
|
159
166
|
def namespace(space = nil, options = {}, &block)
|
160
|
-
|
167
|
+
@namespace_description = nil unless instance_variable_defined?(:@namespace_description) && @namespace_description
|
168
|
+
|
169
|
+
if space || block
|
161
170
|
within_namespace do
|
162
171
|
previous_namespace_description = @namespace_description
|
163
172
|
@namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
|
164
173
|
nest(block) do
|
165
|
-
if space
|
166
|
-
namespace_stackable(:namespace, Namespace.new(space, options))
|
167
|
-
end
|
174
|
+
namespace_stackable(:namespace, Namespace.new(space, **options)) if space
|
168
175
|
end
|
169
176
|
@namespace_description = previous_namespace_description
|
170
177
|
end
|
@@ -193,7 +200,7 @@ module Grape
|
|
193
200
|
@endpoints = []
|
194
201
|
end
|
195
202
|
|
196
|
-
#
|
203
|
+
# This method allows you to quickly define a parameter route segment
|
197
204
|
# in your API.
|
198
205
|
#
|
199
206
|
# @param param [Symbol] The name of the parameter you wish to declare.
|
data/lib/grape/dsl/settings.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
4
6
|
module DSL
|
5
|
-
# Keeps track of settings (
|
7
|
+
# Keeps track of settings (implemented as key-value pairs, grouped by
|
6
8
|
# types), in two contexts: top-level settings which apply globally no
|
7
9
|
# matter where they're defined, and inheritable settings which apply only
|
8
10
|
# in the current scope and scopes nested under it.
|
@@ -13,7 +15,7 @@ module Grape
|
|
13
15
|
|
14
16
|
# Fetch our top-level settings, which apply to all endpoints in the API.
|
15
17
|
def top_level_setting
|
16
|
-
@top_level_setting ||=
|
18
|
+
@top_level_setting ||= build_top_level_setting
|
17
19
|
end
|
18
20
|
|
19
21
|
# Fetch our current inheritable settings, which are inherited by
|
@@ -101,12 +103,14 @@ module Grape
|
|
101
103
|
def namespace_stackable_with_hash(key)
|
102
104
|
settings = get_or_set :namespace_stackable, key, nil
|
103
105
|
return if settings.blank?
|
106
|
+
|
104
107
|
settings.each_with_object({}) { |value, result| result.deep_merge!(value) }
|
105
108
|
end
|
106
109
|
|
107
110
|
def namespace_reverse_stackable_with_hash(key)
|
108
111
|
settings = get_or_set :namespace_reverse_stackable, key, nil
|
109
112
|
return if settings.blank?
|
113
|
+
|
110
114
|
result = {}
|
111
115
|
settings.each do |setting|
|
112
116
|
setting.each do |field, value|
|
@@ -152,16 +156,30 @@ module Grape
|
|
152
156
|
|
153
157
|
# Execute the block within a context where our inheritable settings are forked
|
154
158
|
# to a new copy (see #namespace_start).
|
155
|
-
def within_namespace(&
|
159
|
+
def within_namespace(&block)
|
156
160
|
namespace_start
|
157
161
|
|
158
|
-
result = yield if
|
162
|
+
result = yield if block
|
159
163
|
|
160
164
|
namespace_end
|
161
165
|
reset_validations!
|
162
166
|
|
163
167
|
result
|
164
168
|
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
# Builds the current class :inheritable_setting. If available, it inherits from
|
173
|
+
# the superclass's :inheritable_setting.
|
174
|
+
def build_top_level_setting
|
175
|
+
Grape::Util::InheritableSetting.new.tap do |setting|
|
176
|
+
# Doesn't try to inherit settings from +Grape::API::Instance+ which also responds to
|
177
|
+
# +inheritable_setting+, however, it doesn't contain any user-defined settings.
|
178
|
+
# Otherwise, it would lead to an extra instance of +Grape::Util::InheritableSetting+
|
179
|
+
# in the chain for every endpoint.
|
180
|
+
setting.inherit_from superclass.inheritable_setting if defined?(superclass) && superclass.respond_to?(:inheritable_setting) && superclass != Grape::API::Instance
|
181
|
+
end
|
182
|
+
end
|
165
183
|
end
|
166
184
|
end
|
167
185
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/concern'
|
2
4
|
|
3
5
|
module Grape
|
@@ -8,7 +10,24 @@ module Grape
|
|
8
10
|
include Grape::DSL::Configuration
|
9
11
|
|
10
12
|
module ClassMethods
|
11
|
-
# Clears all defined parameters and validations.
|
13
|
+
# Clears all defined parameters and validations. The main purpose of it is to clean up
|
14
|
+
# settings, so next endpoint won't interfere with previous one.
|
15
|
+
#
|
16
|
+
# params do
|
17
|
+
# # params for the endpoint below this block
|
18
|
+
# end
|
19
|
+
# post '/current' do
|
20
|
+
# # whatever
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # somewhere between them the reset_validations! method gets called
|
24
|
+
#
|
25
|
+
# params do
|
26
|
+
# # params for the endpoint below this block
|
27
|
+
# end
|
28
|
+
# post '/next' do
|
29
|
+
# # whatever
|
30
|
+
# end
|
12
31
|
def reset_validations!
|
13
32
|
unset_namespace_stackable :declared_params
|
14
33
|
unset_namespace_stackable :validations
|
@@ -27,10 +46,11 @@ module Grape
|
|
27
46
|
setting = description_field(:params)
|
28
47
|
setting ||= description_field(:params, {})
|
29
48
|
Array(names).each do |name|
|
30
|
-
|
31
|
-
setting[
|
49
|
+
full_name = name[:full_name].to_s
|
50
|
+
setting[full_name] ||= {}
|
51
|
+
setting[full_name].merge!(opts)
|
32
52
|
|
33
|
-
namespace_stackable(:params,
|
53
|
+
namespace_stackable(:params, full_name => opts)
|
34
54
|
end
|
35
55
|
end
|
36
56
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Grape.eager_load!
|
4
|
+
Grape::Http.eager_load!
|
5
|
+
Grape::Exceptions.eager_load!
|
6
|
+
Grape::Extensions.eager_load!
|
7
|
+
Grape::Extensions::ActiveSupport.eager_load!
|
8
|
+
Grape::Extensions::Hashie.eager_load!
|
9
|
+
Grape::Middleware.eager_load!
|
10
|
+
Grape::Middleware::Auth.eager_load!
|
11
|
+
Grape::Middleware::Versioner.eager_load!
|
12
|
+
Grape::Util.eager_load!
|
13
|
+
Grape::ErrorFormatter.eager_load!
|
14
|
+
Grape::Formatter.eager_load!
|
15
|
+
Grape::Parser.eager_load!
|
16
|
+
Grape::DSL.eager_load!
|
17
|
+
Grape::API.eager_load!
|
18
|
+
Grape::Presenters.eager_load!
|
19
|
+
Grape::ServeStream.eager_load!
|
20
|
+
Rack::Head # AutoLoads the Rack::Head
|
data/lib/grape/endpoint.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Grape
|
2
4
|
# An Endpoint is the proxy scope in which all routing
|
3
5
|
# blocks are executed. In other words, any methods
|
@@ -18,7 +20,8 @@ module Grape
|
|
18
20
|
def before_each(new_setup = false, &block)
|
19
21
|
@before_each ||= []
|
20
22
|
if new_setup == false
|
21
|
-
return @before_each unless
|
23
|
+
return @before_each unless block
|
24
|
+
|
22
25
|
@before_each << block
|
23
26
|
else
|
24
27
|
@before_each = [new_setup]
|
@@ -44,9 +47,7 @@ module Grape
|
|
44
47
|
# @return [Proc]
|
45
48
|
# @raise [NameError] an instance method with the same name already exists
|
46
49
|
def generate_api_method(method_name, &block)
|
47
|
-
|
48
|
-
raise NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name")
|
49
|
-
end
|
50
|
+
raise NameError.new("method #{method_name.inspect} already exists and cannot be used as an unbound method name") if method_defined?(method_name)
|
50
51
|
|
51
52
|
define_method(method_name, &block)
|
52
53
|
method = instance_method(method_name)
|
@@ -78,7 +79,10 @@ module Grape
|
|
78
79
|
|
79
80
|
self.inheritable_setting = new_settings.point_in_time_copy
|
80
81
|
|
81
|
-
|
82
|
+
# now +namespace_stackable(:declared_params)+ contains all params defined for
|
83
|
+
# this endpoint and its parents, but later it will be cleaned up,
|
84
|
+
# see +reset_validations!+ in lib/grape/dsl/validations.rb
|
85
|
+
route_setting(:declared_params, namespace_stackable(:declared_params).flatten)
|
82
86
|
route_setting(:saved_validations, namespace_stackable(:validations))
|
83
87
|
|
84
88
|
namespace_stackable(:representations, []) unless namespace_stackable(:representations)
|
@@ -97,11 +101,11 @@ module Grape
|
|
97
101
|
@block = nil
|
98
102
|
|
99
103
|
@status = nil
|
100
|
-
@
|
104
|
+
@stream = nil
|
101
105
|
@body = nil
|
102
106
|
@proc = nil
|
103
107
|
|
104
|
-
return unless
|
108
|
+
return unless block
|
105
109
|
|
106
110
|
@source = block
|
107
111
|
@block = self.class.generate_api_method(method_name, &block)
|
@@ -113,12 +117,9 @@ module Grape
|
|
113
117
|
inheritable_setting.route[:saved_validations] += namespace_stackable[:validations]
|
114
118
|
parent_declared_params = namespace_stackable[:declared_params]
|
115
119
|
|
116
|
-
if parent_declared_params
|
117
|
-
inheritable_setting.route[:declared_params] ||= []
|
118
|
-
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten)
|
119
|
-
end
|
120
|
+
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten) if parent_declared_params
|
120
121
|
|
121
|
-
endpoints
|
122
|
+
endpoints&.each { |e| e.inherit_settings(namespace_stackable) }
|
122
123
|
end
|
123
124
|
|
124
125
|
def require_option(options, key)
|
@@ -138,7 +139,7 @@ module Grape
|
|
138
139
|
end
|
139
140
|
|
140
141
|
def reset_routes!
|
141
|
-
endpoints
|
142
|
+
endpoints&.each(&:reset_routes!)
|
142
143
|
@namespace = nil
|
143
144
|
@routes = nil
|
144
145
|
end
|
@@ -150,13 +151,9 @@ module Grape
|
|
150
151
|
reset_routes!
|
151
152
|
routes.each do |route|
|
152
153
|
methods = [route.request_method]
|
153
|
-
if !namespace_inheritable(:do_not_route_head) && route.request_method == Grape::Http::Headers::GET
|
154
|
-
methods << Grape::Http::Headers::HEAD
|
155
|
-
end
|
154
|
+
methods << Grape::Http::Headers::HEAD if !namespace_inheritable(:do_not_route_head) && route.request_method == Grape::Http::Headers::GET
|
156
155
|
methods.each do |method|
|
157
|
-
|
158
|
-
route = Grape::Router::Route.new(method, route.origin, route.attributes.to_h)
|
159
|
-
end
|
156
|
+
route = Grape::Router::Route.new(method, route.origin, **route.attributes.to_h) unless route.request_method == method
|
160
157
|
router.append(route.apply(self))
|
161
158
|
end
|
162
159
|
end
|
@@ -167,8 +164,8 @@ module Grape
|
|
167
164
|
route_options = prepare_default_route_attributes
|
168
165
|
map_routes do |method, path|
|
169
166
|
path = prepare_path(path)
|
170
|
-
params = merge_route_options(route_options.merge(suffix: path.suffix))
|
171
|
-
route = Router::Route.new(method, path.path, params)
|
167
|
+
params = merge_route_options(**route_options.merge(suffix: path.suffix))
|
168
|
+
route = Router::Route.new(method, path.path, **params)
|
172
169
|
route.apply(self)
|
173
170
|
end.flatten
|
174
171
|
end
|
@@ -188,7 +185,7 @@ module Grape
|
|
188
185
|
requirements: prepare_routes_requirements,
|
189
186
|
prefix: namespace_inheritable(:root_prefix),
|
190
187
|
anchor: options[:route_options].fetch(:anchor, true),
|
191
|
-
settings: inheritable_setting.route.except(:
|
188
|
+
settings: inheritable_setting.route.except(:declared_params, :saved_validations),
|
192
189
|
forward_match: options[:forward_match]
|
193
190
|
}
|
194
191
|
end
|
@@ -196,11 +193,12 @@ module Grape
|
|
196
193
|
def prepare_version
|
197
194
|
version = namespace_inheritable(:version) || []
|
198
195
|
return if version.empty?
|
196
|
+
|
199
197
|
version.length == 1 ? version.first.to_s : version
|
200
198
|
end
|
201
199
|
|
202
200
|
def merge_route_options(**default)
|
203
|
-
options[:route_options].clone.
|
201
|
+
options[:route_options].clone.merge!(**default)
|
204
202
|
end
|
205
203
|
|
206
204
|
def map_routes
|
@@ -230,7 +228,7 @@ module Grape
|
|
230
228
|
# Return the collection of endpoints within this endpoint.
|
231
229
|
# This is the case when an Grape::API mounts another Grape::API.
|
232
230
|
def endpoints
|
233
|
-
options[:app].endpoints if options[:app]
|
231
|
+
options[:app].endpoints if options[:app].respond_to?(:endpoints)
|
234
232
|
end
|
235
233
|
|
236
234
|
def equals?(e)
|
@@ -245,32 +243,37 @@ module Grape
|
|
245
243
|
@request = Grape::Request.new(env, build_params_with: namespace_inheritable(:build_params_with))
|
246
244
|
@params = @request.params
|
247
245
|
@headers = @request.headers
|
246
|
+
begin
|
247
|
+
cookies.read(@request)
|
248
|
+
self.class.run_before_each(self)
|
249
|
+
run_filters befores, :before
|
250
|
+
|
251
|
+
if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
|
252
|
+
raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allowed_methods)) unless options?
|
253
|
+
|
254
|
+
header 'Allow', allowed_methods
|
255
|
+
response_object = ''
|
256
|
+
status 204
|
257
|
+
else
|
258
|
+
run_filters before_validations, :before_validation
|
259
|
+
run_validators validations, request
|
260
|
+
run_filters after_validations, :after_validation
|
261
|
+
response_object = execute
|
262
|
+
end
|
248
263
|
|
249
|
-
|
250
|
-
|
251
|
-
run_filters befores, :before
|
252
|
-
|
253
|
-
if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
|
254
|
-
raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) unless options?
|
255
|
-
header 'Allow', allowed_methods
|
256
|
-
response_object = ''
|
257
|
-
status 204
|
258
|
-
else
|
259
|
-
run_filters before_validations, :before_validation
|
260
|
-
run_validators validations, request
|
261
|
-
run_filters after_validations, :after_validation
|
262
|
-
response_object = @block ? @block.call(self) : nil
|
263
|
-
end
|
264
|
+
run_filters afters, :after
|
265
|
+
cookies.write(header)
|
264
266
|
|
265
|
-
|
266
|
-
|
267
|
+
# status verifies body presence when DELETE
|
268
|
+
@body ||= response_object
|
267
269
|
|
268
|
-
|
269
|
-
|
270
|
+
# The body commonly is an Array of Strings, the application instance itself, or a Stream-like object
|
271
|
+
response_object = stream || [body]
|
270
272
|
|
271
|
-
|
272
|
-
|
273
|
-
|
273
|
+
[status, header, response_object]
|
274
|
+
ensure
|
275
|
+
run_filters finallies, :finally
|
276
|
+
end
|
274
277
|
end
|
275
278
|
end
|
276
279
|
|
@@ -321,6 +324,10 @@ module Grape
|
|
321
324
|
|
322
325
|
private :build_stack, :build_helpers
|
323
326
|
|
327
|
+
def execute
|
328
|
+
@block ? @block.call(self) : nil
|
329
|
+
end
|
330
|
+
|
324
331
|
def helpers
|
325
332
|
lazy_initialize! && @helpers
|
326
333
|
end
|
@@ -341,23 +348,21 @@ module Grape
|
|
341
348
|
def run_validators(validator_factories, request)
|
342
349
|
validation_errors = []
|
343
350
|
|
344
|
-
validators = validator_factories.map(
|
351
|
+
validators = validator_factories.map { |options| Grape::Validations::ValidatorFactory.create_validator(**options) }
|
345
352
|
|
346
353
|
ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
|
347
354
|
validators.each do |validator|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
break if validator.fail_fast?
|
356
|
-
end
|
355
|
+
validator.validate(request)
|
356
|
+
rescue Grape::Exceptions::Validation => e
|
357
|
+
validation_errors << e
|
358
|
+
break if validator.fail_fast?
|
359
|
+
rescue Grape::Exceptions::ValidationArrayErrors => e
|
360
|
+
validation_errors.concat e.errors
|
361
|
+
break if validator.fail_fast?
|
357
362
|
end
|
358
363
|
end
|
359
364
|
|
360
|
-
validation_errors.any? && raise(Grape::Exceptions::ValidationErrors
|
365
|
+
validation_errors.any? && raise(Grape::Exceptions::ValidationErrors.new(errors: validation_errors, headers: header))
|
361
366
|
end
|
362
367
|
|
363
368
|
def run_filters(filters, type = :other)
|
@@ -384,6 +389,10 @@ module Grape
|
|
384
389
|
namespace_stackable(:afters) || []
|
385
390
|
end
|
386
391
|
|
392
|
+
def finallies
|
393
|
+
namespace_stackable(:finallies) || []
|
394
|
+
end
|
395
|
+
|
387
396
|
def validations
|
388
397
|
route_setting(:saved_validations) || []
|
389
398
|
end
|