grape 0.17.0 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -3
- data/Dangerfile +1 -80
- data/Gemfile +1 -1
- data/Gemfile.lock +69 -51
- data/README.md +42 -1
- data/UPGRADING.md +2 -2
- data/grape.gemspec +1 -1
- data/lib/grape/api.rb +5 -15
- data/lib/grape/cookies.rb +1 -1
- data/lib/grape/dsl/inside_route.rb +2 -3
- data/lib/grape/dsl/request_response.rb +1 -1
- data/lib/grape/endpoint.rb +19 -7
- data/lib/grape/error_formatter.rb +2 -2
- data/lib/grape/exceptions/base.rb +18 -18
- data/lib/grape/exceptions/validation.rb +6 -7
- data/lib/grape/exceptions/validation_errors.rb +5 -5
- data/lib/grape/formatter.rb +2 -2
- data/lib/grape/locale/en.yml +1 -0
- data/lib/grape/middleware/auth/base.rb +2 -2
- data/lib/grape/middleware/base.rb +2 -2
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/stack.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +1 -1
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/parser.rb +2 -2
- data/lib/grape/presenters/presenter.rb +1 -1
- data/lib/grape/router.rb +6 -6
- data/lib/grape/router/pattern.rb +7 -7
- data/lib/grape/router/route.rb +3 -3
- data/lib/grape/util/env.rb +1 -1
- data/lib/grape/validations/params_scope.rb +15 -7
- data/lib/grape/validations/validators/allow_blank.rb +0 -13
- data/lib/grape/validations/validators/base.rb +8 -1
- data/lib/grape/validations/validators/default.rb +1 -3
- data/lib/grape/validations/validators/presence.rb +0 -5
- data/lib/grape/validations/validators/values.rb +17 -3
- data/lib/grape/version.rb +1 -1
- data/pkg/grape-0.18.0.gem +0 -0
- data/spec/grape/api_spec.rb +41 -0
- data/spec/grape/exceptions/validation_spec.rb +1 -1
- data/spec/grape/middleware/stack_spec.rb +20 -0
- data/spec/grape/validations/params_scope_spec.rb +190 -58
- data/spec/grape/validations/validators/allow_blank_spec.rb +22 -7
- data/spec/grape/validations/validators/coerce_spec.rb +6 -6
- data/spec/grape/validations/validators/values_spec.rb +146 -0
- data/spec/grape/validations_spec.rb +28 -0
- metadata +6 -6
data/UPGRADING.md
CHANGED
@@ -526,7 +526,7 @@ Permitted and default parameter values are now only evaluated lazily for each re
|
|
526
526
|
|
527
527
|
```ruby
|
528
528
|
params do
|
529
|
-
optional :v, values: -> { [:x, :y] }, default: -> { :z }
|
529
|
+
optional :v, values: -> { [:x, :y] }, default: -> { :z }
|
530
530
|
end
|
531
531
|
```
|
532
532
|
|
@@ -534,7 +534,7 @@ Remove the proc to get the previous behavior.
|
|
534
534
|
|
535
535
|
```ruby
|
536
536
|
params do
|
537
|
-
optional :v, values: [:x, :y], default: :z
|
537
|
+
optional :v, values: [:x, :y], default: :z
|
538
538
|
end
|
539
539
|
```
|
540
540
|
|
data/grape.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.license = 'MIT'
|
14
14
|
|
15
15
|
s.add_runtime_dependency 'rack', '>= 1.3.0'
|
16
|
-
s.add_runtime_dependency '
|
16
|
+
s.add_runtime_dependency 'mustermann-grape', '~> 0.4.0'
|
17
17
|
s.add_runtime_dependency 'rack-accept'
|
18
18
|
s.add_runtime_dependency 'activesupport'
|
19
19
|
s.add_runtime_dependency 'multi_json', '>= 1.3.2'
|
data/lib/grape/api.rb
CHANGED
@@ -173,7 +173,6 @@ module Grape
|
|
173
173
|
without_versioning do
|
174
174
|
routes_map.each do |_, config|
|
175
175
|
methods = config[:methods]
|
176
|
-
path = config[:path]
|
177
176
|
allowed_methods = methods.dup
|
178
177
|
|
179
178
|
unless self.class.namespace_inheritable(:do_not_route_head)
|
@@ -182,8 +181,8 @@ module Grape
|
|
182
181
|
|
183
182
|
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ')
|
184
183
|
|
185
|
-
unless self.class.namespace_inheritable(:do_not_route_options)
|
186
|
-
|
184
|
+
unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
|
185
|
+
config[:endpoint].options[:options_route_enabled] = true
|
187
186
|
end
|
188
187
|
|
189
188
|
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
|
@@ -193,24 +192,15 @@ module Grape
|
|
193
192
|
end
|
194
193
|
end
|
195
194
|
|
196
|
-
# Generate an 'OPTIONS' route for a pre-exisiting user defined route
|
197
|
-
def generate_options_method(path, allow_header, options = {})
|
198
|
-
self.class.options(path, options) do
|
199
|
-
header 'Allow', allow_header
|
200
|
-
status 204
|
201
|
-
''
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
195
|
# Generate a route that returns an HTTP 405 response for a user defined
|
206
196
|
# path on methods not specified
|
207
|
-
def generate_not_allowed_method(pattern,
|
208
|
-
not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) -
|
197
|
+
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
198
|
+
not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
|
209
199
|
not_allowed_methods << Grape::Http::Headers::OPTIONS if self.class.namespace_inheritable(:do_not_route_options)
|
210
200
|
|
211
201
|
return if not_allowed_methods.empty?
|
212
202
|
|
213
|
-
@router.associate_routes(pattern,
|
203
|
+
@router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
|
214
204
|
end
|
215
205
|
|
216
206
|
# Allows definition of endpoints that ignore the versioning configuration
|
data/lib/grape/cookies.rb
CHANGED
@@ -97,9 +97,8 @@ module Grape
|
|
97
97
|
# @param options [Hash] The options used when redirect.
|
98
98
|
# :permanent, default false.
|
99
99
|
# :body, default a short message including the URL.
|
100
|
-
def redirect(url,
|
101
|
-
|
102
|
-
body_message = options.fetch(:body, nil)
|
100
|
+
def redirect(url, permanent: false, body: nil, **_options)
|
101
|
+
body_message = body
|
103
102
|
if permanent
|
104
103
|
status 301
|
105
104
|
body_message ||= "This resource has been moved permanently to #{url}."
|
@@ -88,7 +88,7 @@ module Grape
|
|
88
88
|
# rescue_from CustomError
|
89
89
|
# end
|
90
90
|
#
|
91
|
-
# @overload rescue_from(*exception_classes, options
|
91
|
+
# @overload rescue_from(*exception_classes, **options)
|
92
92
|
# @param [Array] exception_classes A list of classes that you want to rescue, or
|
93
93
|
# the symbol :all to rescue from all exceptions.
|
94
94
|
# @param [Block] block Execution block to handle the given exception.
|
data/lib/grape/endpoint.rb
CHANGED
@@ -194,8 +194,8 @@ module Grape
|
|
194
194
|
version.length == 1 ? version.first.to_s : version
|
195
195
|
end
|
196
196
|
|
197
|
-
def merge_route_options(default
|
198
|
-
options[:route_options].clone.reverse_merge(default)
|
197
|
+
def merge_route_options(**default)
|
198
|
+
options[:route_options].clone.reverse_merge(**default)
|
199
199
|
end
|
200
200
|
|
201
201
|
def map_routes
|
@@ -248,16 +248,21 @@ module Grape
|
|
248
248
|
|
249
249
|
run_filters befores, :before
|
250
250
|
|
251
|
-
allowed_methods = env[Grape::Env::
|
252
|
-
raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) if allowed_methods
|
251
|
+
allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS]
|
252
|
+
raise Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allowed_methods) if !options? && allowed_methods
|
253
253
|
|
254
254
|
run_filters before_validations, :before_validation
|
255
|
-
|
256
255
|
run_validators validations, request
|
257
|
-
|
258
256
|
run_filters after_validations, :after_validation
|
259
257
|
|
260
|
-
response_object =
|
258
|
+
response_object =
|
259
|
+
if options?
|
260
|
+
header 'Allow', allowed_methods
|
261
|
+
status 204
|
262
|
+
''
|
263
|
+
else
|
264
|
+
@block ? @block.call(self) : nil
|
265
|
+
end
|
261
266
|
run_filters afters, :after
|
262
267
|
cookies.write(header)
|
263
268
|
|
@@ -338,8 +343,10 @@ module Grape
|
|
338
343
|
validator.validate(request)
|
339
344
|
rescue Grape::Exceptions::Validation => e
|
340
345
|
validation_errors << e
|
346
|
+
break if validator.fail_fast?
|
341
347
|
rescue Grape::Exceptions::ValidationArrayErrors => e
|
342
348
|
validation_errors += e.errors
|
349
|
+
break if validator.fail_fast?
|
343
350
|
end
|
344
351
|
end
|
345
352
|
|
@@ -373,5 +380,10 @@ module Grape
|
|
373
380
|
def validations
|
374
381
|
route_setting(:saved_validations) || []
|
375
382
|
end
|
383
|
+
|
384
|
+
def options?
|
385
|
+
options[:options_route_enabled] &&
|
386
|
+
env[Grape::Http::Headers::REQUEST_METHOD] == Grape::Http::Headers::OPTIONS
|
387
|
+
end
|
376
388
|
end
|
377
389
|
end
|
@@ -17,8 +17,8 @@ module Grape
|
|
17
17
|
builtin_formatters.merge(default_elements).merge(options[:error_formatters] || {})
|
18
18
|
end
|
19
19
|
|
20
|
-
def formatter_for(api_format, options
|
21
|
-
spec = formatters(options)[api_format]
|
20
|
+
def formatter_for(api_format, **options)
|
21
|
+
spec = formatters(**options)[api_format]
|
22
22
|
case spec
|
23
23
|
when nil
|
24
24
|
options[:default_error_formatter] || Grape::ErrorFormatter::Txt
|
@@ -7,10 +7,10 @@ module Grape
|
|
7
7
|
|
8
8
|
attr_reader :status, :message, :headers
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@status
|
12
|
-
@message =
|
13
|
-
@headers =
|
10
|
+
def initialize(status: nil, message: nil, headers: nil, **_options)
|
11
|
+
@status = status
|
12
|
+
@message = message
|
13
|
+
@headers = headers
|
14
14
|
end
|
15
15
|
|
16
16
|
def [](index)
|
@@ -22,12 +22,12 @@ module Grape
|
|
22
22
|
# TODO: translate attribute first
|
23
23
|
# if BASE_ATTRIBUTES_KEY.key respond to a string message, then short_message is returned
|
24
24
|
# if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
|
25
|
-
def compose_message(key, attributes
|
26
|
-
short_message = translate_message(key, attributes)
|
25
|
+
def compose_message(key, **attributes)
|
26
|
+
short_message = translate_message(key, **attributes)
|
27
27
|
if short_message.is_a? Hash
|
28
|
-
@problem = problem(key, attributes)
|
29
|
-
@summary = summary(key, attributes)
|
30
|
-
@resolution = resolution(key, attributes)
|
28
|
+
@problem = problem(key, **attributes)
|
29
|
+
@summary = summary(key, **attributes)
|
30
|
+
@resolution = resolution(key, **attributes)
|
31
31
|
[['Problem', @problem], ['Summary', @summary], ['Resolution', @resolution]].reduce('') do |message, detail_array|
|
32
32
|
message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
|
33
33
|
message
|
@@ -49,20 +49,20 @@ module Grape
|
|
49
49
|
translate_message("#{key}.resolution".to_sym, attributes)
|
50
50
|
end
|
51
51
|
|
52
|
-
def translate_attributes(keys, options
|
52
|
+
def translate_attributes(keys, **options)
|
53
53
|
keys.map do |key|
|
54
|
-
translate("#{BASE_ATTRIBUTES_KEY}.#{key}",
|
54
|
+
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key, **options)
|
55
55
|
end.join(', ')
|
56
56
|
end
|
57
57
|
|
58
|
-
def translate_attribute(key, options
|
59
|
-
translate("#{BASE_ATTRIBUTES_KEY}.#{key}",
|
58
|
+
def translate_attribute(key, **options)
|
59
|
+
translate("#{BASE_ATTRIBUTES_KEY}.#{key}", default: key, **options)
|
60
60
|
end
|
61
61
|
|
62
|
-
def translate_message(key, options
|
62
|
+
def translate_message(key, **options)
|
63
63
|
case key
|
64
64
|
when Symbol
|
65
|
-
translate("#{BASE_MESSAGES_KEY}.#{key}",
|
65
|
+
translate("#{BASE_MESSAGES_KEY}.#{key}", default: '', **options)
|
66
66
|
when Proc
|
67
67
|
key.call
|
68
68
|
else
|
@@ -70,9 +70,9 @@ module Grape
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def translate(key, options
|
74
|
-
message = ::I18n.translate(key, options)
|
75
|
-
message.present? ? message : ::I18n.translate(key,
|
73
|
+
def translate(key, **options)
|
74
|
+
message = ::I18n.translate(key, **options)
|
75
|
+
message.present? ? message : ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
@@ -6,14 +6,13 @@ module Grape
|
|
6
6
|
attr_accessor :params
|
7
7
|
attr_accessor :message_key
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
args[:message] = translate_message(args[:message])
|
9
|
+
def initialize(params:, message: nil, **args)
|
10
|
+
@params = params
|
11
|
+
if message
|
12
|
+
@message_key = message if message.is_a?(Symbol)
|
13
|
+
args[:message] = translate_message(message)
|
15
14
|
end
|
16
|
-
super
|
15
|
+
super(args)
|
17
16
|
end
|
18
17
|
|
19
18
|
# remove all the unnecessary stuff from Grape::Exceptions::Base like status
|
@@ -7,14 +7,14 @@ module Grape
|
|
7
7
|
|
8
8
|
attr_reader :errors
|
9
9
|
|
10
|
-
def initialize(
|
10
|
+
def initialize(errors: [], headers: {}, **_options)
|
11
11
|
@errors = {}
|
12
|
-
|
12
|
+
errors.each do |validation_error|
|
13
13
|
@errors[validation_error.params] ||= []
|
14
14
|
@errors[validation_error.params] << validation_error
|
15
15
|
end
|
16
16
|
|
17
|
-
super message: full_messages.join(', '), status: 400, headers:
|
17
|
+
super message: full_messages.join(', '), status: 400, headers: headers
|
18
18
|
end
|
19
19
|
|
20
20
|
def each
|
@@ -25,7 +25,7 @@ module Grape
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def as_json(_opts
|
28
|
+
def as_json(**_opts)
|
29
29
|
errors.map do |k, v|
|
30
30
|
{
|
31
31
|
params: k,
|
@@ -34,7 +34,7 @@ module Grape
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
def to_json(_opts
|
37
|
+
def to_json(**_opts)
|
38
38
|
as_json.to_json
|
39
39
|
end
|
40
40
|
|
data/lib/grape/formatter.rb
CHANGED
@@ -17,8 +17,8 @@ module Grape
|
|
17
17
|
builtin_formmaters.merge(default_elements).merge(options[:formatters] || {})
|
18
18
|
end
|
19
19
|
|
20
|
-
def formatter_for(api_format, options
|
21
|
-
spec = formatters(options)[api_format]
|
20
|
+
def formatter_for(api_format, **options)
|
21
|
+
spec = formatters(**options)[api_format]
|
22
22
|
case spec
|
23
23
|
when nil
|
24
24
|
->(obj, _env) { obj }
|
data/lib/grape/locale/en.yml
CHANGED
@@ -10,9 +10,9 @@ module Grape
|
|
10
10
|
|
11
11
|
# @param [Rack Application] app The standard argument for a Rack middleware.
|
12
12
|
# @param [Hash] options A hash of options, simply stored for use by subclasses.
|
13
|
-
def initialize(app, options
|
13
|
+
def initialize(app, **options)
|
14
14
|
@app = app
|
15
|
-
@options = default_options.merge(options)
|
15
|
+
@options = default_options.merge(**options)
|
16
16
|
end
|
17
17
|
|
18
18
|
def default_options
|
@@ -32,7 +32,7 @@ module Grape
|
|
32
32
|
def before
|
33
33
|
strict_header_checks if strict?
|
34
34
|
|
35
|
-
if media_type || env[Grape::Env::
|
35
|
+
if media_type || env[Grape::Env::GRAPE_ALLOWED_METHODS]
|
36
36
|
media_type_header_handler
|
37
37
|
elsif headers_contain_wrong_vendor?
|
38
38
|
fail_with_invalid_accept_header!('API vendor not found.')
|
data/lib/grape/namespace.rb
CHANGED
@@ -10,7 +10,7 @@ module Grape
|
|
10
10
|
# @option options :requirements [Hash] param-regex pairs, all of which must
|
11
11
|
# be met by a request's params for all endpoints in this namespace, or
|
12
12
|
# validation will fail and return a 422.
|
13
|
-
def initialize(space, options
|
13
|
+
def initialize(space, **options)
|
14
14
|
@space = space.to_s
|
15
15
|
@options = options
|
16
16
|
end
|
data/lib/grape/parser.rb
CHANGED
@@ -15,8 +15,8 @@ module Grape
|
|
15
15
|
builtin_parsers.merge(default_elements).merge(options[:parsers] || {})
|
16
16
|
end
|
17
17
|
|
18
|
-
def parser_for(api_format, options
|
19
|
-
spec = parsers(options)[api_format]
|
18
|
+
def parser_for(api_format, **options)
|
19
|
+
spec = parsers(**options)[api_format]
|
20
20
|
case spec
|
21
21
|
when nil
|
22
22
|
nil
|
data/lib/grape/router.rb
CHANGED
@@ -5,7 +5,7 @@ module Grape
|
|
5
5
|
attr_reader :map, :compiled
|
6
6
|
|
7
7
|
class Any < AttributeTranslator
|
8
|
-
def initialize(pattern, attributes
|
8
|
+
def initialize(pattern, **attributes)
|
9
9
|
@pattern = pattern
|
10
10
|
super(attributes)
|
11
11
|
end
|
@@ -42,9 +42,9 @@ module Grape
|
|
42
42
|
map[route.request_method.to_s.upcase] << route
|
43
43
|
end
|
44
44
|
|
45
|
-
def associate_routes(pattern, options
|
45
|
+
def associate_routes(pattern, **options)
|
46
46
|
regexp = /(?<_#{@neutral_map.length}>)#{pattern.to_regexp}/
|
47
|
-
@neutral_map << Any.new(pattern,
|
47
|
+
@neutral_map << Any.new(pattern, regexp: regexp, index: @neutral_map.length, **options)
|
48
48
|
end
|
49
49
|
|
50
50
|
def call(env)
|
@@ -95,7 +95,7 @@ module Grape
|
|
95
95
|
neighbor = greedy_match?(input)
|
96
96
|
return unless neighbor
|
97
97
|
|
98
|
-
(!cascade && neighbor) ?
|
98
|
+
(!cascade && neighbor) ? call_with_allow_headers(env, neighbor.allow_header, neighbor.endpoint) : nil
|
99
99
|
end
|
100
100
|
|
101
101
|
def make_routing_args(default_args, route, input)
|
@@ -132,8 +132,8 @@ module Grape
|
|
132
132
|
@neutral_map.detect { |route| last_match["_#{route.index}"] }
|
133
133
|
end
|
134
134
|
|
135
|
-
def
|
136
|
-
env[Grape::Env::
|
135
|
+
def call_with_allow_headers(env, methods, endpoint)
|
136
|
+
env[Grape::Env::GRAPE_ALLOWED_METHODS] = methods
|
137
137
|
endpoint.call(env)
|
138
138
|
end
|
139
139
|
|