grape 1.3.2 → 1.5.2
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 +82 -2
- data/LICENSE +1 -1
- data/README.md +120 -24
- data/UPGRADING.md +220 -39
- data/lib/grape.rb +3 -2
- data/lib/grape/api.rb +3 -3
- data/lib/grape/api/instance.rb +22 -25
- data/lib/grape/dsl/callbacks.rb +1 -1
- data/lib/grape/dsl/helpers.rb +1 -0
- data/lib/grape/dsl/inside_route.rb +70 -37
- data/lib/grape/dsl/parameters.rb +8 -4
- data/lib/grape/dsl/routing.rb +6 -7
- data/lib/grape/dsl/validations.rb +18 -1
- data/lib/grape/eager_load.rb +1 -1
- data/lib/grape/endpoint.rb +8 -6
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/middleware/auth/base.rb +3 -3
- data/lib/grape/middleware/base.rb +3 -2
- data/lib/grape/middleware/error.rb +11 -13
- data/lib/grape/middleware/formatter.rb +3 -3
- data/lib/grape/middleware/stack.rb +8 -1
- data/lib/grape/request.rb +1 -1
- data/lib/grape/router.rb +25 -39
- data/lib/grape/router/attribute_translator.rb +26 -5
- data/lib/grape/router/route.rb +1 -19
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
- data/lib/grape/util/base_inheritable.rb +2 -2
- data/lib/grape/util/lazy_value.rb +1 -0
- data/lib/grape/validations/attributes_iterator.rb +8 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/params_scope.rb +9 -7
- data/lib/grape/validations/single_attribute_iterator.rb +1 -1
- data/lib/grape/validations/types.rb +1 -4
- data/lib/grape/validations/types/array_coercer.rb +14 -5
- data/lib/grape/validations/types/build_coercer.rb +1 -5
- data/lib/grape/validations/types/custom_type_coercer.rb +15 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/primitive_coercer.rb +9 -3
- data/lib/grape/validations/types/set_coercer.rb +6 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
- data/lib/grape/validations/validator_factory.rb +1 -1
- data/lib/grape/validations/validators/as.rb +1 -1
- data/lib/grape/validations/validators/base.rb +8 -8
- data/lib/grape/validations/validators/coerce.rb +8 -14
- data/lib/grape/validations/validators/default.rb +3 -5
- data/lib/grape/validations/validators/except_values.rb +1 -1
- data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
- data/lib/grape/validations/validators/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/instance_spec.rb +50 -0
- data/spec/grape/api_remount_spec.rb +9 -4
- data/spec/grape/api_spec.rb +75 -0
- data/spec/grape/dsl/inside_route_spec.rb +182 -33
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +0 -521
- data/spec/grape/entity_spec.rb +7 -1
- data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
- data/spec/grape/middleware/error_spec.rb +1 -1
- data/spec/grape/middleware/formatter_spec.rb +1 -1
- data/spec/grape/middleware/stack_spec.rb +1 -0
- data/spec/grape/request_spec.rb +1 -1
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
- data/spec/grape/validations/params_scope_spec.rb +26 -0
- data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +65 -5
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/validators/coerce_spec.rb +223 -25
- data/spec/grape/validations/validators/default_spec.rb +170 -0
- data/spec/grape/validations/validators/except_values_spec.rb +1 -0
- data/spec/grape/validations/validators/values_spec.rb +1 -1
- data/spec/grape/validations_spec.rb +290 -18
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/shared/versioning_examples.rb +20 -20
- data/spec/spec_helper.rb +0 -10
- data/spec/support/chunks.rb +14 -0
- data/spec/support/versioned_helpers.rb +4 -6
- metadata +20 -9
data/lib/grape.rb
CHANGED
@@ -12,6 +12,7 @@ require 'active_support/core_ext/hash/indifferent_access'
|
|
12
12
|
require 'active_support/core_ext/object/blank'
|
13
13
|
require 'active_support/core_ext/array/extract_options'
|
14
14
|
require 'active_support/core_ext/array/wrap'
|
15
|
+
require 'active_support/core_ext/array/conversions'
|
15
16
|
require 'active_support/core_ext/hash/deep_merge'
|
16
17
|
require 'active_support/core_ext/hash/reverse_merge'
|
17
18
|
require 'active_support/core_ext/hash/except'
|
@@ -206,12 +207,12 @@ module Grape
|
|
206
207
|
end
|
207
208
|
end
|
208
209
|
|
209
|
-
module
|
210
|
+
module ServeStream
|
210
211
|
extend ::ActiveSupport::Autoload
|
211
212
|
eager_autoload do
|
212
|
-
autoload :FileResponse
|
213
213
|
autoload :FileBody
|
214
214
|
autoload :SendfileResponse
|
215
|
+
autoload :StreamResponse
|
215
216
|
end
|
216
217
|
end
|
217
218
|
end
|
data/lib/grape/api.rb
CHANGED
@@ -30,7 +30,7 @@ module Grape
|
|
30
30
|
# an instance that will be used to create the set up but will not be mounted
|
31
31
|
def initial_setup(base_instance_parent)
|
32
32
|
@instances = []
|
33
|
-
@setup =
|
33
|
+
@setup = Set.new
|
34
34
|
@base_parent = base_instance_parent
|
35
35
|
@base_instance = mount_instance
|
36
36
|
end
|
@@ -87,10 +87,10 @@ module Grape
|
|
87
87
|
end
|
88
88
|
|
89
89
|
# The remountable class can have a configuration hash to provide some dynamic class-level variables.
|
90
|
-
# For instance, a
|
90
|
+
# For instance, a description could be done using: `desc configuration[:description]` if it may vary
|
91
91
|
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
92
92
|
# too much, you may actually want to provide a new API rather than remount it.
|
93
|
-
def mount_instance(opts
|
93
|
+
def mount_instance(**opts)
|
94
94
|
instance = Class.new(@base_parent)
|
95
95
|
instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
|
96
96
|
instance.base = self
|
data/lib/grape/api/instance.rb
CHANGED
@@ -192,36 +192,15 @@ module Grape
|
|
192
192
|
# will return an HTTP 405 response for any HTTP method that the resource
|
193
193
|
# cannot handle.
|
194
194
|
def add_head_not_allowed_methods_and_options_methods
|
195
|
-
|
196
|
-
|
197
|
-
self.class.endpoints.each do |endpoint|
|
198
|
-
routes = endpoint.routes
|
199
|
-
routes.each do |route|
|
200
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
201
|
-
route_key = route.pattern.to_regexp
|
202
|
-
routes_map[route_key] ||= {}
|
203
|
-
route_settings = routes_map[route_key]
|
204
|
-
route_settings[:pattern] = route.pattern
|
205
|
-
route_settings[:requirements] = route.requirements
|
206
|
-
route_settings[:path] = route.origin
|
207
|
-
route_settings[:methods] ||= []
|
208
|
-
route_settings[:methods] << route.request_method
|
209
|
-
route_settings[:endpoint] = route.app
|
210
|
-
|
211
|
-
# using the :any shorthand produces [nil] for route methods, substitute all manually
|
212
|
-
route_settings[:methods] = Grape::Http::Headers::SUPPORTED_METHODS if route_settings[:methods].include?('*')
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
195
|
+
versioned_route_configs = collect_route_config_per_pattern
|
216
196
|
# The paths we collected are prepared (cf. Path#prepare), so they
|
217
197
|
# contain already versioning information when using path versioning.
|
218
198
|
# Disable versioning so adding a route won't prepend versioning
|
219
199
|
# informations again.
|
220
200
|
without_root_prefix do
|
221
201
|
without_versioning do
|
222
|
-
|
223
|
-
|
224
|
-
allowed_methods = methods.dup
|
202
|
+
versioned_route_configs.each do |config|
|
203
|
+
allowed_methods = config[:methods].dup
|
225
204
|
|
226
205
|
unless self.class.namespace_inheritable(:do_not_route_head)
|
227
206
|
allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
|
@@ -240,6 +219,25 @@ module Grape
|
|
240
219
|
end
|
241
220
|
end
|
242
221
|
|
222
|
+
def collect_route_config_per_pattern
|
223
|
+
all_routes = self.class.endpoints.map(&:routes).flatten
|
224
|
+
routes_by_regexp = all_routes.group_by { |route| route.pattern.to_regexp }
|
225
|
+
|
226
|
+
# Build the configuration based on the first endpoint and the collection of methods supported.
|
227
|
+
routes_by_regexp.values.map do |routes|
|
228
|
+
last_route = routes.last # Most of the configuration is taken from the last endpoint
|
229
|
+
matching_wildchar = routes.any? { |route| route.request_method == '*' }
|
230
|
+
{
|
231
|
+
options: {},
|
232
|
+
pattern: last_route.pattern,
|
233
|
+
requirements: last_route.requirements,
|
234
|
+
path: last_route.origin,
|
235
|
+
endpoint: last_route.app,
|
236
|
+
methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method)
|
237
|
+
}
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
243
241
|
# Generate a route that returns an HTTP 405 response for a user defined
|
244
242
|
# path on methods not specified
|
245
243
|
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
@@ -251,7 +249,6 @@ module Grape
|
|
251
249
|
end
|
252
250
|
not_allowed_methods = supported_methods - allowed_methods
|
253
251
|
return if not_allowed_methods.empty?
|
254
|
-
|
255
252
|
@router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
|
256
253
|
end
|
257
254
|
|
data/lib/grape/dsl/callbacks.rb
CHANGED
@@ -59,7 +59,7 @@ module Grape
|
|
59
59
|
# end
|
60
60
|
# end
|
61
61
|
#
|
62
|
-
# This will make sure that the ApiLogger is opened and
|
62
|
+
# This will make sure that the ApiLogger is opened and closed around every
|
63
63
|
# request
|
64
64
|
# @param ensured_block [Proc] The block to be executed after every api_call
|
65
65
|
def finally(&block)
|
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -28,36 +28,38 @@ module Grape
|
|
28
28
|
# Methods which should not be available in filters until the before filter
|
29
29
|
# has completed
|
30
30
|
module PostBeforeFilter
|
31
|
-
def declared(passed_params, options = {}, declared_params = nil)
|
31
|
+
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
|
32
32
|
options = options.reverse_merge(include_missing: true, include_parent_namespaces: true)
|
33
33
|
declared_params ||= optioned_declared_params(**options)
|
34
34
|
|
35
35
|
if passed_params.is_a?(Array)
|
36
|
-
declared_array(passed_params, options, declared_params)
|
36
|
+
declared_array(passed_params, options, declared_params, params_nested_path)
|
37
37
|
else
|
38
|
-
declared_hash(passed_params, options, declared_params)
|
38
|
+
declared_hash(passed_params, options, declared_params, params_nested_path)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
def declared_array(passed_params, options, declared_params)
|
44
|
+
def declared_array(passed_params, options, declared_params, params_nested_path)
|
45
45
|
passed_params.map do |passed_param|
|
46
|
-
declared(passed_param || {}, options, declared_params)
|
46
|
+
declared(passed_param || {}, options, declared_params, params_nested_path)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def declared_hash(passed_params, options, declared_params)
|
50
|
+
def declared_hash(passed_params, options, declared_params, params_nested_path)
|
51
51
|
declared_params.each_with_object(passed_params.class.new) do |declared_param, memo|
|
52
52
|
if declared_param.is_a?(Hash)
|
53
53
|
declared_param.each_pair do |declared_parent_param, declared_children_params|
|
54
|
+
params_nested_path_dup = params_nested_path.dup
|
55
|
+
params_nested_path_dup << declared_parent_param.to_s
|
54
56
|
next unless options[:include_missing] || passed_params.key?(declared_parent_param)
|
55
57
|
|
56
58
|
passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
|
57
59
|
memo_key = optioned_param_key(declared_parent_param, options)
|
58
60
|
|
59
|
-
memo[memo_key] = handle_passed_param(
|
60
|
-
declared(passed_children_params, options, declared_children_params)
|
61
|
+
memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
|
62
|
+
declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
else
|
@@ -68,30 +70,37 @@ module Grape
|
|
68
70
|
|
69
71
|
next unless options[:include_missing] || passed_params.key?(declared_param) || (param_renaming && passed_params.key?(param_renaming))
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
73
|
+
memo_key = optioned_param_key(param_renaming || declared_param, options)
|
74
|
+
passed_param = passed_params[param_renaming || declared_param]
|
75
|
+
|
76
|
+
params_nested_path_dup = params_nested_path.dup
|
77
|
+
params_nested_path_dup << declared_param.to_s
|
78
|
+
memo[memo_key] = passed_param || handle_passed_param(params_nested_path_dup) do
|
79
|
+
passed_param
|
75
80
|
end
|
76
81
|
end
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
80
|
-
def handle_passed_param(
|
81
|
-
|
82
|
-
end
|
85
|
+
def handle_passed_param(params_nested_path, has_passed_children = false, &_block)
|
86
|
+
return yield if has_passed_children
|
83
87
|
|
84
|
-
|
85
|
-
|
86
|
-
end
|
88
|
+
key = params_nested_path[0]
|
89
|
+
key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
|
87
90
|
|
88
|
-
|
89
|
-
|
90
|
-
route_options_params
|
91
|
-
end
|
91
|
+
route_options_params = options[:route_options][:params] || {}
|
92
|
+
type = route_options_params.dig(key, :type)
|
93
|
+
has_children = route_options_params.keys.any? { |k| k != key && k.start_with?(key) }
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
+
if type == 'Hash' && !has_children
|
96
|
+
{}
|
97
|
+
elsif type == 'Array' || type&.start_with?('[') && !type&.include?(',')
|
98
|
+
[]
|
99
|
+
elsif type == 'Set' || type&.start_with?('#<Set')
|
100
|
+
Set.new
|
101
|
+
else
|
102
|
+
yield
|
103
|
+
end
|
95
104
|
end
|
96
105
|
|
97
106
|
def optioned_param_key(declared_param, options)
|
@@ -101,10 +110,10 @@ module Grape
|
|
101
110
|
def optioned_declared_params(**options)
|
102
111
|
declared_params = if options[:include_parent_namespaces]
|
103
112
|
# Declared params including parent namespaces
|
104
|
-
route_setting(:
|
113
|
+
route_setting(:declared_params)
|
105
114
|
else
|
106
115
|
# Declared params at current namespace
|
107
|
-
|
116
|
+
namespace_stackable(:declared_params).last || []
|
108
117
|
end
|
109
118
|
|
110
119
|
raise ArgumentError, 'Tried to filter for declared parameters but none exist.' unless declared_params
|
@@ -256,23 +265,36 @@ module Grape
|
|
256
265
|
body false
|
257
266
|
end
|
258
267
|
|
259
|
-
#
|
268
|
+
# Deprecated method to send files to the client. Use `sendfile` or `stream`
|
269
|
+
def file(value = nil)
|
270
|
+
if value.is_a?(String)
|
271
|
+
warn '[DEPRECATION] Use sendfile or stream to send files.'
|
272
|
+
sendfile(value)
|
273
|
+
elsif !value.is_a?(NilClass)
|
274
|
+
warn '[DEPRECATION] Use stream to use a Stream object.'
|
275
|
+
stream(value)
|
276
|
+
else
|
277
|
+
warn '[DEPRECATION] Use sendfile or stream to send files.'
|
278
|
+
sendfile
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Allows you to send a file to the client via sendfile.
|
260
283
|
#
|
261
284
|
# @example
|
262
285
|
# get '/file' do
|
263
|
-
#
|
286
|
+
# sendfile FileStreamer.new(...)
|
264
287
|
# end
|
265
288
|
#
|
266
289
|
# GET /file # => "contents of file"
|
267
|
-
def
|
290
|
+
def sendfile(value = nil)
|
268
291
|
if value.is_a?(String)
|
269
|
-
file_body = Grape::
|
270
|
-
@
|
292
|
+
file_body = Grape::ServeStream::FileBody.new(value)
|
293
|
+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
|
271
294
|
elsif !value.is_a?(NilClass)
|
272
|
-
|
273
|
-
@file = Grape::ServeFile::FileResponse.new(value)
|
295
|
+
raise ArgumentError, 'Argument must be a file path'
|
274
296
|
else
|
275
|
-
|
297
|
+
stream
|
276
298
|
end
|
277
299
|
end
|
278
300
|
|
@@ -292,10 +314,21 @@ module Grape
|
|
292
314
|
# * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/chunked.rb
|
293
315
|
# * https://github.com/rack/rack/blob/99293fa13d86cd48021630fcc4bd5acc9de5bdc3/lib/rack/etag.rb
|
294
316
|
def stream(value = nil)
|
317
|
+
return if value.nil? && @stream.nil?
|
318
|
+
|
295
319
|
header 'Content-Length', nil
|
296
320
|
header 'Transfer-Encoding', nil
|
297
321
|
header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
|
298
|
-
|
322
|
+
if value.is_a?(String)
|
323
|
+
file_body = Grape::ServeStream::FileBody.new(value)
|
324
|
+
@stream = Grape::ServeStream::StreamResponse.new(file_body)
|
325
|
+
elsif value.respond_to?(:each)
|
326
|
+
@stream = Grape::ServeStream::StreamResponse.new(value)
|
327
|
+
elsif !value.is_a?(NilClass)
|
328
|
+
raise ArgumentError, 'Stream object must respond to :each.'
|
329
|
+
else
|
330
|
+
@stream
|
331
|
+
end
|
299
332
|
end
|
300
333
|
|
301
334
|
# Allows you to make use of Grape Entities by setting
|
@@ -366,7 +399,7 @@ module Grape
|
|
366
399
|
entity_class = options.delete(:with)
|
367
400
|
|
368
401
|
if entity_class.nil?
|
369
|
-
# entity class not
|
402
|
+
# entity class not explicitly defined, auto-detect from relation#klass or first object in the collection
|
370
403
|
object_class = if object.respond_to?(:klass)
|
371
404
|
object.klass
|
372
405
|
else
|
@@ -388,7 +421,7 @@ module Grape
|
|
388
421
|
def entity_representation_for(entity_class, object, options)
|
389
422
|
embeds = { env: env }
|
390
423
|
embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
|
391
|
-
entity_class.represent(object, embeds.merge(options))
|
424
|
+
entity_class.represent(object, **embeds.merge(options))
|
392
425
|
end
|
393
426
|
end
|
394
427
|
end
|
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -72,7 +72,7 @@ module Grape
|
|
72
72
|
|
73
73
|
# Require one or more parameters for the current endpoint.
|
74
74
|
#
|
75
|
-
# @param attrs list of
|
75
|
+
# @param attrs list of parameters names, or, if :using is
|
76
76
|
# passed as an option, which keys to include (:all or :none) from
|
77
77
|
# the :using hash. The last key can be a hash, which specifies
|
78
78
|
# options for the parameters
|
@@ -227,13 +227,17 @@ module Grape
|
|
227
227
|
|
228
228
|
alias group requires
|
229
229
|
|
230
|
-
|
230
|
+
class EmptyOptionalValue; end
|
231
|
+
|
232
|
+
def map_params(params, element, is_array = false)
|
231
233
|
if params.is_a?(Array)
|
232
234
|
params.map do |el|
|
233
|
-
map_params(el, element)
|
235
|
+
map_params(el, element, true)
|
234
236
|
end
|
235
237
|
elsif params.is_a?(Hash)
|
236
|
-
params[element] || {}
|
238
|
+
params[element] || (@optional && is_array ? EmptyOptionalValue : {})
|
239
|
+
elsif params == EmptyOptionalValue
|
240
|
+
EmptyOptionalValue
|
237
241
|
else
|
238
242
|
{}
|
239
243
|
end
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -79,11 +79,12 @@ module Grape
|
|
79
79
|
namespace_inheritable(:do_not_route_options, true)
|
80
80
|
end
|
81
81
|
|
82
|
-
def mount(mounts, opts
|
82
|
+
def mount(mounts, *opts)
|
83
83
|
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
|
84
84
|
mounts.each_pair do |app, path|
|
85
85
|
if app.respond_to?(:mount_instance)
|
86
|
-
|
86
|
+
opts_with = opts.any? ? opts.shift[:with] : {}
|
87
|
+
mount({ app.mount_instance(configuration: opts_with) => path })
|
87
88
|
next
|
88
89
|
end
|
89
90
|
in_setting = inheritable_setting
|
@@ -151,7 +152,7 @@ module Grape
|
|
151
152
|
end
|
152
153
|
|
153
154
|
# Declare a "namespace", which prefixes all subordinate routes with its
|
154
|
-
# name. Any endpoints within a namespace,
|
155
|
+
# name. Any endpoints within a namespace, group, resource or segment,
|
155
156
|
# etc., will share their parent context as well as any configuration
|
156
157
|
# done in the namespace context.
|
157
158
|
#
|
@@ -170,9 +171,7 @@ module Grape
|
|
170
171
|
previous_namespace_description = @namespace_description
|
171
172
|
@namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
|
172
173
|
nest(block) do
|
173
|
-
if space
|
174
|
-
namespace_stackable(:namespace, Namespace.new(space, **options))
|
175
|
-
end
|
174
|
+
namespace_stackable(:namespace, Namespace.new(space, **options)) if space
|
176
175
|
end
|
177
176
|
@namespace_description = previous_namespace_description
|
178
177
|
end
|
@@ -201,7 +200,7 @@ module Grape
|
|
201
200
|
@endpoints = []
|
202
201
|
end
|
203
202
|
|
204
|
-
#
|
203
|
+
# This method allows you to quickly define a parameter route segment
|
205
204
|
# in your API.
|
206
205
|
#
|
207
206
|
# @param param [Symbol] The name of the parameter you wish to declare.
|
@@ -10,7 +10,24 @@ module Grape
|
|
10
10
|
include Grape::DSL::Configuration
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
# 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
|
14
31
|
def reset_validations!
|
15
32
|
unset_namespace_stackable :declared_params
|
16
33
|
unset_namespace_stackable :validations
|
data/lib/grape/eager_load.rb
CHANGED
data/lib/grape/endpoint.rb
CHANGED
@@ -80,7 +80,10 @@ module Grape
|
|
80
80
|
|
81
81
|
self.inheritable_setting = new_settings.point_in_time_copy
|
82
82
|
|
83
|
-
|
83
|
+
# now +namespace_stackable(:declared_params)+ contains all params defined for
|
84
|
+
# this endpoint and its parents, but later it will be cleaned up,
|
85
|
+
# see +reset_validations!+ in lib/grape/dsl/validations.rb
|
86
|
+
route_setting(:declared_params, namespace_stackable(:declared_params).flatten)
|
84
87
|
route_setting(:saved_validations, namespace_stackable(:validations))
|
85
88
|
|
86
89
|
namespace_stackable(:representations, []) unless namespace_stackable(:representations)
|
@@ -99,7 +102,7 @@ module Grape
|
|
99
102
|
@block = nil
|
100
103
|
|
101
104
|
@status = nil
|
102
|
-
@
|
105
|
+
@stream = nil
|
103
106
|
@body = nil
|
104
107
|
@proc = nil
|
105
108
|
|
@@ -116,7 +119,6 @@ module Grape
|
|
116
119
|
parent_declared_params = namespace_stackable[:declared_params]
|
117
120
|
|
118
121
|
if parent_declared_params
|
119
|
-
inheritable_setting.route[:declared_params] ||= []
|
120
122
|
inheritable_setting.route[:declared_params].concat(parent_declared_params.flatten)
|
121
123
|
end
|
122
124
|
|
@@ -190,7 +192,7 @@ module Grape
|
|
190
192
|
requirements: prepare_routes_requirements,
|
191
193
|
prefix: namespace_inheritable(:root_prefix),
|
192
194
|
anchor: options[:route_options].fetch(:anchor, true),
|
193
|
-
settings: inheritable_setting.route.except(:
|
195
|
+
settings: inheritable_setting.route.except(:declared_params, :saved_validations),
|
194
196
|
forward_match: options[:forward_match]
|
195
197
|
}
|
196
198
|
end
|
@@ -271,8 +273,8 @@ module Grape
|
|
271
273
|
# status verifies body presence when DELETE
|
272
274
|
@body ||= response_object
|
273
275
|
|
274
|
-
# The body commonly is an Array of Strings, the application instance itself, or a
|
275
|
-
response_object =
|
276
|
+
# The body commonly is an Array of Strings, the application instance itself, or a Stream-like object
|
277
|
+
response_object = stream || [body]
|
276
278
|
|
277
279
|
[status, header, response_object]
|
278
280
|
ensure
|