grape 2.0.0 → 2.4.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 +151 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +404 -334
- data/UPGRADING.md +279 -7
- data/grape.gemspec +8 -8
- data/lib/grape/api/instance.rb +34 -66
- data/lib/grape/api.rb +47 -70
- data/lib/grape/content_types.rb +13 -10
- data/lib/grape/cookies.rb +31 -24
- data/lib/grape/dry_types.rb +0 -2
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/desc.rb +49 -44
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +8 -4
- data/lib/grape/dsl/inside_route.rb +67 -54
- data/lib/grape/dsl/parameters.rb +10 -9
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/dsl/routing.rb +34 -17
- data/lib/grape/dsl/validations.rb +13 -0
- data/lib/grape/endpoint.rb +120 -118
- data/lib/grape/{util/env.rb → env.rb} +0 -5
- data/lib/grape/error_formatter/base.rb +51 -21
- data/lib/grape/error_formatter/json.rb +7 -15
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +11 -17
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +5 -25
- data/lib/grape/exceptions/base.rb +18 -30
- data/lib/grape/exceptions/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/validation.rb +5 -6
- data/lib/grape/exceptions/validation_array_errors.rb +1 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -6
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
- data/lib/grape/extensions/hash.rb +7 -2
- data/lib/grape/extensions/hashie/mash.rb +3 -5
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +4 -6
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +7 -25
- data/lib/grape/{util/json.rb → json.rb} +1 -3
- data/lib/grape/locale/en.yml +46 -42
- data/lib/grape/middleware/auth/base.rb +11 -34
- data/lib/grape/middleware/auth/dsl.rb +23 -31
- data/lib/grape/middleware/base.rb +41 -23
- data/lib/grape/middleware/error.rb +77 -76
- data/lib/grape/middleware/formatter.rb +48 -79
- data/lib/grape/middleware/globals.rb +1 -3
- data/lib/grape/middleware/stack.rb +26 -37
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +74 -0
- data/lib/grape/middleware/versioner/header.rb +59 -126
- data/lib/grape/middleware/versioner/param.rb +4 -25
- data/lib/grape/middleware/versioner/path.rb +10 -34
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/namespace.rb +4 -5
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +38 -60
- data/lib/grape/request.rb +161 -30
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +45 -31
- data/lib/grape/router/route.rb +28 -57
- data/lib/grape/router.rb +56 -43
- data/lib/grape/util/base_inheritable.rb +4 -4
- data/lib/grape/util/cache.rb +0 -3
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_values.rb +0 -2
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +1 -6
- data/lib/grape/util/strict_hash_configuration.rb +3 -3
- data/lib/grape/validations/attributes_doc.rb +38 -36
- data/lib/grape/validations/attributes_iterator.rb +1 -0
- data/lib/grape/validations/contract_scope.rb +34 -0
- data/lib/grape/validations/params_scope.rb +36 -32
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +9 -15
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +0 -2
- data/lib/grape/validations/types/set_coercer.rb +0 -3
- data/lib/grape/validations/types.rb +0 -3
- data/lib/grape/validations/validator_factory.rb +2 -2
- data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
- data/lib/grape/validations/validators/base.rb +8 -11
- data/lib/grape/validations/validators/coerce_validator.rb +1 -1
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +6 -2
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
- data/lib/grape/validations/validators/except_values_validator.rb +2 -2
- data/lib/grape/validations/validators/length_validator.rb +49 -0
- data/lib/grape/validations/validators/presence_validator.rb +1 -1
- data/lib/grape/validations/validators/regexp_validator.rb +2 -2
- data/lib/grape/validations/validators/values_validator.rb +20 -57
- data/lib/grape/validations.rb +8 -21
- data/lib/grape/version.rb +1 -1
- data/lib/grape/{util/xml.rb → xml.rb} +1 -1
- data/lib/grape.rb +42 -274
- metadata +45 -44
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/http/headers.rb +0 -71
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/validations/types/build_coercer.rb +0 -94
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'grape/dsl/headers'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
module DSL
|
7
5
|
module InsideRoute
|
@@ -28,14 +26,20 @@ module Grape
|
|
28
26
|
# has completed
|
29
27
|
module PostBeforeFilter
|
30
28
|
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
|
31
|
-
options
|
32
|
-
declared_params ||= optioned_declared_params(
|
29
|
+
options.reverse_merge!(include_missing: true, include_parent_namespaces: true, evaluate_given: false)
|
30
|
+
declared_params ||= optioned_declared_params(options[:include_parent_namespaces])
|
33
31
|
|
34
|
-
if passed_params.is_a?(Array)
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
res = if passed_params.is_a?(Array)
|
33
|
+
declared_array(passed_params, options, declared_params, params_nested_path)
|
34
|
+
else
|
35
|
+
declared_hash(passed_params, options, declared_params, params_nested_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
if (key_maps = namespace_stackable(:contract_key_map))
|
39
|
+
key_maps.each { |key_map| key_map.write(passed_params, res) }
|
38
40
|
end
|
41
|
+
|
42
|
+
res
|
39
43
|
end
|
40
44
|
|
41
45
|
private
|
@@ -75,7 +79,7 @@ module Grape
|
|
75
79
|
else
|
76
80
|
# If it is not a Hash then it does not have children.
|
77
81
|
# Find its value or set it to nil.
|
78
|
-
return unless options[:include_missing] || passed_params.key
|
82
|
+
return unless options[:include_missing] || passed_params.try(:key?, declared_param)
|
79
83
|
|
80
84
|
rename_path = params_nested_path + [declared_param.to_s]
|
81
85
|
renamed_param_name = renamed_params[rename_path]
|
@@ -99,11 +103,11 @@ module Grape
|
|
99
103
|
|
100
104
|
route_options_params = options[:route_options][:params] || {}
|
101
105
|
type = route_options_params.dig(key, :type)
|
102
|
-
has_children = route_options_params.keys.any? { |k| k != key && k.start_with?(key) }
|
106
|
+
has_children = route_options_params.keys.any? { |k| k != key && k.start_with?("#{key}[") }
|
103
107
|
|
104
108
|
if type == 'Hash' && !has_children
|
105
109
|
{}
|
106
|
-
elsif type == 'Array' || (type&.start_with?('[') && type
|
110
|
+
elsif type == 'Array' || (type&.start_with?('[') && type.exclude?(','))
|
107
111
|
[]
|
108
112
|
elsif type == 'Set' || type&.start_with?('#<Set')
|
109
113
|
Set.new
|
@@ -116,8 +120,8 @@ module Grape
|
|
116
120
|
options[:stringify] ? declared_param.to_s : declared_param.to_sym
|
117
121
|
end
|
118
122
|
|
119
|
-
def optioned_declared_params(
|
120
|
-
declared_params = if
|
123
|
+
def optioned_declared_params(include_parent_namespaces)
|
124
|
+
declared_params = if include_parent_namespaces
|
121
125
|
# Declared params including parent namespaces
|
122
126
|
route_setting(:declared_params)
|
123
127
|
else
|
@@ -159,33 +163,57 @@ module Grape
|
|
159
163
|
# end user with the specified message.
|
160
164
|
#
|
161
165
|
# @param message [String] The message to display.
|
162
|
-
# @param status [Integer]
|
166
|
+
# @param status [Integer] The HTTP Status Code. Defaults to default_error_status, 500 if not set.
|
163
167
|
# @param additional_headers [Hash] Addtional headers for the response.
|
164
|
-
|
165
|
-
|
168
|
+
# @param backtrace [Array<String>] The backtrace of the exception that caused the error.
|
169
|
+
# @param original_exception [Exception] The original exception that caused the error.
|
170
|
+
def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
|
171
|
+
status = self.status(status || namespace_inheritable(:default_error_status))
|
166
172
|
headers = additional_headers.present? ? header.merge(additional_headers) : header
|
167
|
-
throw :error,
|
173
|
+
throw :error,
|
174
|
+
message: message,
|
175
|
+
status: status,
|
176
|
+
headers: headers,
|
177
|
+
backtrace: backtrace,
|
178
|
+
original_exception: original_exception
|
179
|
+
end
|
180
|
+
|
181
|
+
# Creates a Rack response based on the provided message, status, and headers.
|
182
|
+
# The content type in the headers is set to the default content type unless provided.
|
183
|
+
# The message is HTML-escaped if the content type is 'text/html'.
|
184
|
+
#
|
185
|
+
# @param message [String] The content of the response.
|
186
|
+
# @param status [Integer] The HTTP status code.
|
187
|
+
# @params headers [Hash] (optional) Headers for the response
|
188
|
+
# (default: {Rack::CONTENT_TYPE => content_type}).
|
189
|
+
#
|
190
|
+
# Returns:
|
191
|
+
# A Rack::Response object containing the specified message, status, and headers.
|
192
|
+
#
|
193
|
+
def rack_response(message, status = 200, headers = { Rack::CONTENT_TYPE => content_type })
|
194
|
+
Grape.deprecator.warn('The rack_response method has been deprecated, use error! instead.')
|
195
|
+
message = Rack::Utils.escape_html(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
|
196
|
+
Rack::Response.new(Array.wrap(message), Rack::Utils.status_code(status), headers)
|
168
197
|
end
|
169
198
|
|
170
199
|
# Redirect to a new url.
|
171
200
|
#
|
172
201
|
# @param url [String] The url to be redirect.
|
173
|
-
# @param
|
174
|
-
#
|
175
|
-
|
176
|
-
def redirect(url, permanent: false, body: nil, **_options)
|
202
|
+
# @param permanent [Boolean] default false.
|
203
|
+
# @param body default a short message including the URL.
|
204
|
+
def redirect(url, permanent: false, body: nil)
|
177
205
|
body_message = body
|
178
206
|
if permanent
|
179
207
|
status 301
|
180
208
|
body_message ||= "This resource has been moved permanently to #{url}."
|
181
|
-
elsif
|
209
|
+
elsif http_version == 'HTTP/1.1' && !request.get?
|
182
210
|
status 303
|
183
211
|
body_message ||= "An alternate resource is located at #{url}."
|
184
212
|
else
|
185
213
|
status 302
|
186
214
|
body_message ||= "This resource has been moved temporarily to #{url}."
|
187
215
|
end
|
188
|
-
header
|
216
|
+
header 'Location', url
|
189
217
|
content_type 'text/plain'
|
190
218
|
body body_message
|
191
219
|
end
|
@@ -204,10 +232,9 @@ module Grape
|
|
204
232
|
when nil
|
205
233
|
return @status if instance_variable_defined?(:@status) && @status
|
206
234
|
|
207
|
-
|
208
|
-
when Grape::Http::Headers::POST
|
235
|
+
if request.post?
|
209
236
|
201
|
210
|
-
|
237
|
+
elsif request.delete?
|
211
238
|
if instance_variable_defined?(:@body) && @body.present?
|
212
239
|
200
|
213
240
|
else
|
@@ -230,18 +257,6 @@ module Grape
|
|
230
257
|
end
|
231
258
|
end
|
232
259
|
|
233
|
-
# Set or get a cookie
|
234
|
-
#
|
235
|
-
# @example
|
236
|
-
# cookies[:mycookie] = 'mycookie val'
|
237
|
-
# cookies['mycookie-string'] = 'mycookie string val'
|
238
|
-
# cookies[:more] = { value: '123', expires: Time.at(0) }
|
239
|
-
# cookies.delete :more
|
240
|
-
#
|
241
|
-
def cookies
|
242
|
-
@cookies ||= Cookies.new
|
243
|
-
end
|
244
|
-
|
245
260
|
# Allows you to define the response body as something other than the
|
246
261
|
# return value.
|
247
262
|
#
|
@@ -277,20 +292,6 @@ module Grape
|
|
277
292
|
body false
|
278
293
|
end
|
279
294
|
|
280
|
-
# Deprecated method to send files to the client. Use `sendfile` or `stream`
|
281
|
-
def file(value = nil)
|
282
|
-
if value.is_a?(String)
|
283
|
-
Grape.deprecator.warn('Use sendfile or stream to send files.')
|
284
|
-
sendfile(value)
|
285
|
-
elsif !value.is_a?(NilClass)
|
286
|
-
Grape.deprecator.warn('Use stream to use a Stream object.')
|
287
|
-
stream(value)
|
288
|
-
else
|
289
|
-
Grape.deprecator.warn('Use sendfile or stream to send files.')
|
290
|
-
sendfile
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
295
|
# Allows you to send a file to the client via sendfile.
|
295
296
|
#
|
296
297
|
# @example
|
@@ -329,7 +330,7 @@ module Grape
|
|
329
330
|
return if value.nil? && @stream.nil?
|
330
331
|
|
331
332
|
header Rack::CONTENT_LENGTH, nil
|
332
|
-
header
|
333
|
+
header 'Transfer-Encoding', nil
|
333
334
|
header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)
|
334
335
|
if value.is_a?(String)
|
335
336
|
file_body = Grape::ServeStream::FileBody.new(value)
|
@@ -434,7 +435,19 @@ module Grape
|
|
434
435
|
def entity_representation_for(entity_class, object, options)
|
435
436
|
embeds = { env: env }
|
436
437
|
embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
|
437
|
-
entity_class.represent(object, **embeds
|
438
|
+
entity_class.represent(object, **embeds, **options)
|
439
|
+
end
|
440
|
+
|
441
|
+
def http_version
|
442
|
+
env.fetch('HTTP_VERSION') { env[Rack::SERVER_PROTOCOL] }
|
443
|
+
end
|
444
|
+
|
445
|
+
def api_format(format)
|
446
|
+
env[Grape::Env::API_FORMAT] = format
|
447
|
+
end
|
448
|
+
|
449
|
+
def context
|
450
|
+
self
|
438
451
|
end
|
439
452
|
end
|
440
453
|
end
|
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -23,14 +23,14 @@ module Grape
|
|
23
23
|
# class API < Grape::API
|
24
24
|
# desc "Get collection"
|
25
25
|
# params do
|
26
|
-
# build_with
|
26
|
+
# build_with :hashie_mash
|
27
27
|
# requires :user_id, type: Integer
|
28
28
|
# end
|
29
29
|
# get do
|
30
30
|
# params['user_id']
|
31
31
|
# end
|
32
32
|
# end
|
33
|
-
def build_with(build_with
|
33
|
+
def build_with(build_with)
|
34
34
|
@api.namespace_inheritable(:build_params_with, build_with)
|
35
35
|
end
|
36
36
|
|
@@ -130,13 +130,13 @@ module Grape
|
|
130
130
|
|
131
131
|
opts = attrs.extract_options!.clone
|
132
132
|
opts[:presence] = { value: true, message: opts[:message] }
|
133
|
-
opts = @group.
|
133
|
+
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
134
134
|
|
135
135
|
if opts[:using]
|
136
136
|
require_required_and_optional_fields(attrs.first, opts)
|
137
137
|
else
|
138
138
|
validate_attributes(attrs, opts, &block)
|
139
|
-
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs,
|
139
|
+
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, opts.slice(:as))
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
@@ -149,7 +149,7 @@ module Grape
|
|
149
149
|
|
150
150
|
opts = attrs.extract_options!.clone
|
151
151
|
type = opts[:type]
|
152
|
-
opts = @group.
|
152
|
+
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
153
153
|
|
154
154
|
# check type for optional parameter group
|
155
155
|
if attrs && block
|
@@ -162,7 +162,7 @@ module Grape
|
|
162
162
|
else
|
163
163
|
validate_attributes(attrs, opts, &block)
|
164
164
|
|
165
|
-
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs,
|
165
|
+
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, opts.slice(:as))
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
@@ -170,7 +170,8 @@ module Grape
|
|
170
170
|
# @param (see #requires)
|
171
171
|
# @option (see #requires)
|
172
172
|
def with(*attrs, &block)
|
173
|
-
|
173
|
+
new_group_attrs = [@group, attrs.clone.first].compact.reduce(&:deep_merge)
|
174
|
+
new_group_scope([new_group_attrs], &block)
|
174
175
|
end
|
175
176
|
|
176
177
|
# Disallow the given parameters to be present in the same request.
|
@@ -230,7 +231,7 @@ module Grape
|
|
230
231
|
|
231
232
|
alias group requires
|
232
233
|
|
233
|
-
class EmptyOptionalValue; end
|
234
|
+
class EmptyOptionalValue; end # rubocop:disable Lint/EmptyClass
|
234
235
|
|
235
236
|
def map_params(params, element, is_array = false)
|
236
237
|
if params.is_a?(Array)
|
@@ -250,7 +251,7 @@ module Grape
|
|
250
251
|
# @return hash of parameters relevant for the current scope
|
251
252
|
# @api private
|
252
253
|
def params(params)
|
253
|
-
params = @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
254
|
+
params = @parent.params_meeting_dependency.presence || @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
254
255
|
params = map_params(params, @element) if instance_variable_defined?(:@element) && @element
|
255
256
|
params
|
256
257
|
end
|
@@ -17,18 +17,16 @@ module Grape
|
|
17
17
|
# Specify the format for the API's serializers.
|
18
18
|
# May be `:json`, `:xml`, `:txt`, etc.
|
19
19
|
def format(new_format = nil)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
namespace_inheritable(:format)
|
31
|
-
end
|
20
|
+
return namespace_inheritable(:format) unless new_format
|
21
|
+
|
22
|
+
symbolic_new_format = new_format.to_sym
|
23
|
+
namespace_inheritable(:format, symbolic_new_format)
|
24
|
+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
|
25
|
+
|
26
|
+
content_type = content_types[symbolic_new_format]
|
27
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
|
28
|
+
|
29
|
+
namespace_stackable(:content_types, symbolic_new_format => content_type)
|
32
30
|
end
|
33
31
|
|
34
32
|
# Specify a custom formatter for a content-type.
|
@@ -43,12 +41,10 @@ module Grape
|
|
43
41
|
|
44
42
|
# Specify a default error formatter.
|
45
43
|
def default_error_formatter(new_formatter_name = nil)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
namespace_inheritable(:default_error_formatter)
|
51
|
-
end
|
44
|
+
return namespace_inheritable(:default_error_formatter) unless new_formatter_name
|
45
|
+
|
46
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
|
47
|
+
namespace_inheritable(:default_error_formatter, new_formatter)
|
52
48
|
end
|
53
49
|
|
54
50
|
def error_formatter(format, options)
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -30,7 +30,7 @@ module Grape
|
|
30
30
|
if args.any?
|
31
31
|
options = args.extract_options!
|
32
32
|
options = options.reverse_merge(using: :path)
|
33
|
-
requested_versions = args.flatten
|
33
|
+
requested_versions = args.flatten.map(&:to_s)
|
34
34
|
|
35
35
|
raise Grape::Exceptions::MissingVendorOption.new if options[:using] == :header && !options.key?(:vendor)
|
36
36
|
|
@@ -54,7 +54,7 @@ module Grape
|
|
54
54
|
|
55
55
|
# Define a root URL prefix for your entire API.
|
56
56
|
def prefix(prefix = nil)
|
57
|
-
namespace_inheritable(:root_prefix, prefix)
|
57
|
+
namespace_inheritable(:root_prefix, prefix&.to_s)
|
58
58
|
end
|
59
59
|
|
60
60
|
# Create a scope without affecting the URL.
|
@@ -67,6 +67,10 @@ module Grape
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
def build_with(build_with)
|
71
|
+
namespace_inheritable(:build_params_with, build_with)
|
72
|
+
end
|
73
|
+
|
70
74
|
# Do not route HEAD requests to GET requests automatically.
|
71
75
|
def do_not_route_head!
|
72
76
|
namespace_inheritable(:do_not_route_head, true)
|
@@ -77,6 +81,10 @@ module Grape
|
|
77
81
|
namespace_inheritable(:do_not_route_options, true)
|
78
82
|
end
|
79
83
|
|
84
|
+
def lint!
|
85
|
+
namespace_inheritable(:lint, true)
|
86
|
+
end
|
87
|
+
|
80
88
|
def do_not_document!
|
81
89
|
namespace_inheritable(:do_not_document, true)
|
82
90
|
end
|
@@ -85,8 +93,8 @@ module Grape
|
|
85
93
|
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
|
86
94
|
mounts.each_pair do |app, path|
|
87
95
|
if app.respond_to?(:mount_instance)
|
88
|
-
opts_with = opts.any? ? opts.
|
89
|
-
mount({ app.mount_instance(configuration: opts_with) => path })
|
96
|
+
opts_with = opts.any? ? opts.first[:with] : {}
|
97
|
+
mount({ app.mount_instance(configuration: opts_with) => path }, *opts)
|
90
98
|
next
|
91
99
|
end
|
92
100
|
in_setting = inheritable_setting
|
@@ -103,6 +111,15 @@ module Grape
|
|
103
111
|
change!
|
104
112
|
end
|
105
113
|
|
114
|
+
# When trying to mount multiple times the same endpoint, remove the previous ones
|
115
|
+
# from the list of endpoints if refresh_already_mounted parameter is true
|
116
|
+
refresh_already_mounted = opts.any? ? opts.first[:refresh_already_mounted] : false
|
117
|
+
if refresh_already_mounted && !endpoints.empty?
|
118
|
+
endpoints.delete_if do |endpoint|
|
119
|
+
endpoint.options[:app].to_s == app.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
106
123
|
endpoints << Grape::Endpoint.new(
|
107
124
|
in_setting,
|
108
125
|
method: :any,
|
@@ -145,7 +162,7 @@ module Grape
|
|
145
162
|
reset_validations!
|
146
163
|
end
|
147
164
|
|
148
|
-
Grape::
|
165
|
+
Grape::HTTP_SUPPORTED_METHODS.each do |supported_method|
|
149
166
|
define_method supported_method.downcase do |*args, &block|
|
150
167
|
options = args.extract_options!
|
151
168
|
paths = args.first || ['/']
|
@@ -166,19 +183,12 @@ module Grape
|
|
166
183
|
# end
|
167
184
|
# end
|
168
185
|
def namespace(space = nil, options = {}, &block)
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
@namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
|
175
|
-
nest(block) do
|
176
|
-
namespace_stackable(:namespace, Namespace.new(space, **options)) if space
|
177
|
-
end
|
178
|
-
@namespace_description = previous_namespace_description
|
186
|
+
return Namespace.joined_space_path(namespace_stackable(:namespace)) unless space || block
|
187
|
+
|
188
|
+
within_namespace do
|
189
|
+
nest(block) do
|
190
|
+
namespace_stackable(:namespace, Namespace.new(space, options)) if space
|
179
191
|
end
|
180
|
-
else
|
181
|
-
Namespace.joined_space_path(namespace_stackable(:namespace))
|
182
192
|
end
|
183
193
|
end
|
184
194
|
|
@@ -225,6 +235,13 @@ module Grape
|
|
225
235
|
def versions
|
226
236
|
@versions ||= []
|
227
237
|
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def refresh_mounted_api(mounts, *opts)
|
242
|
+
opts << { refresh_already_mounted: true }
|
243
|
+
mount(mounts, *opts)
|
244
|
+
end
|
228
245
|
end
|
229
246
|
end
|
230
247
|
end
|
@@ -38,6 +38,19 @@ module Grape
|
|
38
38
|
def params(&block)
|
39
39
|
Grape::Validations::ParamsScope.new(api: self, type: Hash, &block)
|
40
40
|
end
|
41
|
+
|
42
|
+
# Declare the contract to be used for the endpoint's parameters.
|
43
|
+
# @param contract [Class<Dry::Validation::Contract> | Dry::Schema::Processor]
|
44
|
+
# The contract or schema to be used for validation. Optional.
|
45
|
+
# @yield a block yielding a new instance of Dry::Schema::Params
|
46
|
+
# subclass, allowing to define the schema inline. When the
|
47
|
+
# +contract+ parameter is a schema, it will be used as a parent. Optional.
|
48
|
+
def contract(contract = nil, &block)
|
49
|
+
raise ArgumentError, 'Either contract or block must be provided' unless contract || block
|
50
|
+
raise ArgumentError, 'Cannot inherit from contract, only schema' if block && contract.respond_to?(:schema)
|
51
|
+
|
52
|
+
Grape::Validations::ContractScope.new(self, contract, &block)
|
53
|
+
end
|
41
54
|
end
|
42
55
|
end
|
43
56
|
end
|