grape 0.14.0 → 0.15.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.

Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -4
  3. data/Gemfile.lock +13 -13
  4. data/README.md +290 -12
  5. data/UPGRADING.md +68 -1
  6. data/gemfiles/rails_3.gemfile +1 -1
  7. data/lib/grape.rb +8 -2
  8. data/lib/grape/api.rb +40 -34
  9. data/lib/grape/dsl/configuration.rb +2 -115
  10. data/lib/grape/dsl/desc.rb +101 -0
  11. data/lib/grape/dsl/headers.rb +16 -0
  12. data/lib/grape/dsl/helpers.rb +5 -9
  13. data/lib/grape/dsl/inside_route.rb +3 -11
  14. data/lib/grape/dsl/logger.rb +20 -0
  15. data/lib/grape/dsl/parameters.rb +12 -10
  16. data/lib/grape/dsl/request_response.rb +17 -4
  17. data/lib/grape/dsl/routing.rb +24 -7
  18. data/lib/grape/dsl/settings.rb +8 -2
  19. data/lib/grape/endpoint.rb +30 -26
  20. data/lib/grape/error_formatter.rb +31 -0
  21. data/lib/grape/error_formatter/base.rb +0 -28
  22. data/lib/grape/error_formatter/json.rb +13 -2
  23. data/lib/grape/error_formatter/txt.rb +3 -1
  24. data/lib/grape/error_formatter/xml.rb +3 -1
  25. data/lib/grape/exceptions/base.rb +11 -4
  26. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  27. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  28. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  29. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  30. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  31. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  32. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
  33. data/lib/grape/exceptions/method_not_allowed.rb +10 -0
  34. data/lib/grape/exceptions/missing_group_type.rb +1 -1
  35. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  36. data/lib/grape/exceptions/missing_option.rb +1 -1
  37. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  38. data/lib/grape/exceptions/unknown_options.rb +1 -1
  39. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  40. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  41. data/lib/grape/exceptions/unsupported_group_type.rb +1 -1
  42. data/lib/grape/exceptions/validation.rb +2 -1
  43. data/lib/grape/formatter.rb +31 -0
  44. data/lib/grape/middleware/base.rb +28 -2
  45. data/lib/grape/middleware/error.rb +24 -1
  46. data/lib/grape/middleware/formatter.rb +4 -3
  47. data/lib/grape/middleware/versioner/param.rb +13 -2
  48. data/lib/grape/parser.rb +29 -0
  49. data/lib/grape/util/sendfile_response.rb +19 -0
  50. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  51. data/lib/grape/validations/params_scope.rb +39 -9
  52. data/lib/grape/validations/types.rb +16 -0
  53. data/lib/grape/validations/validators/all_or_none.rb +1 -1
  54. data/lib/grape/validations/validators/allow_blank.rb +2 -2
  55. data/lib/grape/validations/validators/at_least_one_of.rb +1 -1
  56. data/lib/grape/validations/validators/base.rb +26 -0
  57. data/lib/grape/validations/validators/coerce.rb +16 -14
  58. data/lib/grape/validations/validators/default.rb +1 -1
  59. data/lib/grape/validations/validators/exactly_one_of.rb +10 -1
  60. data/lib/grape/validations/validators/mutual_exclusion.rb +1 -1
  61. data/lib/grape/validations/validators/presence.rb +1 -1
  62. data/lib/grape/validations/validators/regexp.rb +2 -2
  63. data/lib/grape/validations/validators/values.rb +2 -2
  64. data/lib/grape/version.rb +1 -1
  65. data/spec/grape/api/custom_validations_spec.rb +156 -21
  66. data/spec/grape/api/namespace_parameters_in_route_spec.rb +38 -0
  67. data/spec/grape/api/optional_parameters_in_route_spec.rb +43 -0
  68. data/spec/grape/api/required_parameters_in_route_spec.rb +37 -0
  69. data/spec/grape/api_spec.rb +118 -60
  70. data/spec/grape/dsl/configuration_spec.rb +0 -75
  71. data/spec/grape/dsl/desc_spec.rb +77 -0
  72. data/spec/grape/dsl/headers_spec.rb +32 -0
  73. data/spec/grape/dsl/inside_route_spec.rb +0 -18
  74. data/spec/grape/dsl/logger_spec.rb +26 -0
  75. data/spec/grape/dsl/parameters_spec.rb +13 -7
  76. data/spec/grape/dsl/request_response_spec.rb +17 -3
  77. data/spec/grape/dsl/routing_spec.rb +8 -1
  78. data/spec/grape/dsl/settings_spec.rb +42 -0
  79. data/spec/grape/endpoint_spec.rb +60 -9
  80. data/spec/grape/exceptions/validation_errors_spec.rb +2 -2
  81. data/spec/grape/exceptions/validation_spec.rb +7 -0
  82. data/spec/grape/integration/rack_sendfile_spec.rb +44 -0
  83. data/spec/grape/middleware/base_spec.rb +100 -0
  84. data/spec/grape/middleware/exception_spec.rb +1 -2
  85. data/spec/grape/middleware/formatter_spec.rb +12 -2
  86. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
  87. data/spec/grape/middleware/versioner/header_spec.rb +11 -1
  88. data/spec/grape/middleware/versioner/param_spec.rb +105 -1
  89. data/spec/grape/validations/params_scope_spec.rb +77 -0
  90. data/spec/grape/validations/validators/allow_blank_spec.rb +277 -0
  91. data/spec/grape/validations/validators/coerce_spec.rb +91 -0
  92. data/spec/grape/validations/validators/default_spec.rb +6 -0
  93. data/spec/grape/validations/validators/presence_spec.rb +27 -0
  94. data/spec/grape/validations/validators/regexp_spec.rb +36 -0
  95. data/spec/grape/validations/validators/values_spec.rb +44 -0
  96. data/spec/grape/validations_spec.rb +149 -4
  97. data/spec/spec_helper.rb +1 -0
  98. metadata +26 -5
  99. data/lib/grape/formatter/base.rb +0 -31
  100. data/lib/grape/parser/base.rb +0 -29
  101. data/pkg/grape-0.13.0.gem +0 -0
@@ -19,6 +19,7 @@ module Grape
19
19
  end
20
20
 
21
21
  def after
22
+ return unless @app_response
22
23
  status, headers, bodies = *@app_response
23
24
 
24
25
  if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status)
@@ -34,7 +35,7 @@ module Grape
34
35
  headers = ensure_content_type(headers)
35
36
 
36
37
  if bodies.is_a?(Grape::Util::FileResponse)
37
- Rack::Response.new([], status, headers) do |resp|
38
+ Grape::Util::SendfileResponse.new([], status, headers) do |resp|
38
39
  resp.body = bodies.file
39
40
  end
40
41
  else
@@ -49,7 +50,7 @@ module Grape
49
50
 
50
51
  def fetch_formatter(headers, options)
51
52
  api_format = mime_types[headers[Grape::Http::Headers::CONTENT_TYPE]] || env[Grape::Env::API_FORMAT]
52
- Grape::Formatter::Base.formatter_for(api_format, options)
53
+ Grape::Formatter.formatter_for(api_format, options)
53
54
  end
54
55
 
55
56
  # Set the content type header for the API format if it is not already present.
@@ -92,7 +93,7 @@ module Grape
92
93
  fmt = mime_types[request.media_type] if request.media_type
93
94
  fmt ||= options[:default_format]
94
95
  if content_type_for(fmt)
95
- parser = Grape::Parser::Base.parser_for fmt, options
96
+ parser = Grape::Parser.parser_for fmt, options
96
97
  if parser
97
98
  begin
98
99
  body = (env[Grape::Env::API_REQUEST_BODY] = parser.call(body, env))
@@ -21,18 +21,29 @@ module Grape
21
21
  class Param < Base
22
22
  def default_options
23
23
  {
24
- parameter: 'apiver'.freeze
24
+ version_options: {
25
+ parameter: 'apiver'.freeze
26
+ }
25
27
  }
26
28
  end
27
29
 
28
30
  def before
29
- paramkey = options[:parameter]
30
31
  potential_version = Rack::Utils.parse_nested_query(env[Grape::Http::Headers::QUERY_STRING])[paramkey]
31
32
  return if potential_version.nil?
32
33
  throw :error, status: 404, message: '404 API Version Not Found', headers: { Grape::Http::Headers::X_CASCADE => 'pass' } if options[:versions] && !options[:versions].find { |v| v.to_s == potential_version }
33
34
  env[Grape::Env::API_VERSION] = potential_version
34
35
  env[Grape::Env::RACK_REQUEST_QUERY_HASH].delete(paramkey) if env.key? Grape::Env::RACK_REQUEST_QUERY_HASH
35
36
  end
37
+
38
+ private
39
+
40
+ def paramkey
41
+ version_options[:parameter] || default_options[:version_options][:parameter]
42
+ end
43
+
44
+ def version_options
45
+ options[:version_options]
46
+ end
36
47
  end
37
48
  end
38
49
  end
@@ -0,0 +1,29 @@
1
+ module Grape
2
+ module Parser
3
+ class << self
4
+ def builtin_parsers
5
+ {
6
+ json: Grape::Parser::Json,
7
+ jsonapi: Grape::Parser::Json,
8
+ xml: Grape::Parser::Xml
9
+ }
10
+ end
11
+
12
+ def parsers(options)
13
+ builtin_parsers.merge(options[:parsers] || {})
14
+ end
15
+
16
+ def parser_for(api_format, options = {})
17
+ spec = parsers(options)[api_format]
18
+ case spec
19
+ when nil
20
+ nil
21
+ when Symbol
22
+ method(spec)
23
+ else
24
+ spec
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module Grape
2
+ module Util
3
+ # Response should respond to to_path method
4
+ # for using Rack::SendFile middleware
5
+ class SendfileResponse < Rack::Response
6
+ def respond_to?(method_name, include_all = false)
7
+ if method_name == :to_path
8
+ @body.respond_to?(:to_path, include_all)
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ def to_path
15
+ @body.to_path
16
+ end
17
+ end
18
+ end
19
+ end
@@ -98,7 +98,7 @@ module Grape
98
98
  new_config_class = config_class(*args)
99
99
 
100
100
  class_mod.send(:define_method, :config_class) do
101
- @config_context ||= new_config_class
101
+ @config_class ||= new_config_class
102
102
  end
103
103
  end
104
104
  end
@@ -36,7 +36,9 @@ module Grape
36
36
  # validated
37
37
  def should_validate?(parameters)
38
38
  return false if @optional && params(parameters).respond_to?(:all?) && params(parameters).all?(&:blank?)
39
- return false if @dependent_on && params(parameters).try(:[], @dependent_on).blank?
39
+ @dependent_on.each do |dependency|
40
+ return false if params(parameters).try(:[], dependency).blank?
41
+ end if @dependent_on
40
42
  return true if parent.nil?
41
43
  parent.should_validate?(parameters)
42
44
  end
@@ -90,7 +92,11 @@ module Grape
90
92
  # Adds a parameter declaration to our list of validations.
91
93
  # @param attrs [Array] (see Grape::DSL::Parameters#requires)
92
94
  def push_declared_params(attrs)
93
- @declared_params.concat attrs
95
+ if lateral?
96
+ @parent.push_declared_params(attrs)
97
+ else
98
+ @declared_params.concat attrs
99
+ end
94
100
  end
95
101
 
96
102
  private
@@ -141,11 +147,18 @@ module Grape
141
147
  type = attrs[1] ? attrs[1][:type] : nil
142
148
  if attrs.first && !optional
143
149
  fail Grape::Exceptions::MissingGroupTypeError.new if type.nil?
144
- fail Grape::Exceptions::UnsupportedGroupTypeError.new unless [Array, Hash, JSON, Array[JSON]].include?(type)
150
+ fail Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
145
151
  end
146
152
 
147
153
  opts = attrs[1] || { type: Array }
148
- self.class.new(api: @api, element: attrs.first, parent: self, optional: optional, type: opts[:type], &block)
154
+
155
+ self.class.new(
156
+ api: @api,
157
+ element: attrs.first,
158
+ parent: self,
159
+ optional: optional,
160
+ type: opts[:type],
161
+ &block)
149
162
  end
150
163
 
151
164
  # Returns a new parameter scope, not nested under any current-level param
@@ -191,7 +204,7 @@ module Grape
191
204
  default = validations[:default]
192
205
  doc_attrs[:default] = default if validations.key?(:default)
193
206
 
194
- values = validations[:values]
207
+ values = (options_key?(:values, :value, validations)) ? validations[:values][:value] : validations[:values]
195
208
  doc_attrs[:values] = values if values
196
209
 
197
210
  coerce_type = guess_coerce_type(coerce_type, values)
@@ -211,6 +224,7 @@ module Grape
211
224
  if validations.key?(:presence) && validations[:presence]
212
225
  validate('presence', validations[:presence], attrs, doc_attrs)
213
226
  validations.delete(:presence)
227
+ validations.delete(:message) if validations.key?(:message)
214
228
  end
215
229
 
216
230
  # Before we run the rest of the validators, let's handle
@@ -241,8 +255,12 @@ module Grape
241
255
  fail ArgumentError, ':type may not be supplied with :types'
242
256
  end
243
257
 
244
- validations[:coerce] = validations[:type] if validations.key?(:type)
245
- validations[:coerce] = validations.delete(:types) if validations.key?(:types)
258
+ validations[:coerce] = (options_key?(:type, :value, validations) ? validations[:type][:value] : validations[:type]) if validations.key?(:type)
259
+ validations[:coerce_message] = (options_key?(:type, :message, validations) ? validations[:type][:message] : nil) if validations.key?(:type)
260
+ validations[:coerce] = (options_key?(:types, :value, validations) ? validations[:types][:value] : validations[:types]) if validations.key?(:types)
261
+ validations[:coerce_message] = (options_key?(:types, :message, validations) ? validations[:types][:message] : nil) if validations.key?(:types)
262
+
263
+ validations.delete(:types) if validations.key?(:types)
246
264
 
247
265
  coerce_type = validations[:coerce]
248
266
 
@@ -287,11 +305,13 @@ module Grape
287
305
 
288
306
  coerce_options = {
289
307
  type: validations[:coerce],
290
- method: validations[:coerce_with]
308
+ method: validations[:coerce_with],
309
+ message: validations[:coerce_message]
291
310
  }
292
311
  validate('coerce', coerce_options, attrs, doc_attrs)
293
312
  validations.delete(:coerce_with)
294
313
  validations.delete(:coerce)
314
+ validations.delete(:coerce_message)
295
315
  end
296
316
 
297
317
  def guess_coerce_type(coerce_type, values)
@@ -303,7 +323,7 @@ module Grape
303
323
  def check_incompatible_option_values(values, default)
304
324
  return unless values && default
305
325
  return if values.is_a?(Proc) || default.is_a?(Proc)
306
- return if values.include?(default)
326
+ return if values.include?(default) || (Array(default) - Array(values)).empty?
307
327
  fail Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :values, values)
308
328
  end
309
329
 
@@ -329,6 +349,16 @@ module Grape
329
349
  return unless value_types.any? { |v| !v.is_a?(coerce_type) }
330
350
  fail Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values)
331
351
  end
352
+
353
+ def extract_message_option(attrs)
354
+ return nil unless attrs.is_a?(Array)
355
+ opts = attrs.last.is_a?(Hash) ? attrs.pop : {}
356
+ (opts.key?(:message) && !opts[:message].nil?) ? opts.delete(:message) : nil
357
+ end
358
+
359
+ def options_key?(type, key, validations)
360
+ validations[type].respond_to?(:key?) && validations[type].key?(key) && !validations[type][key].nil?
361
+ end
332
362
  end
333
363
  end
334
364
  end
@@ -63,6 +63,13 @@ module Grape
63
63
  Rack::Multipart::UploadedFile => File
64
64
  }
65
65
 
66
+ GROUPS = [
67
+ Array,
68
+ Hash,
69
+ JSON,
70
+ Array[JSON]
71
+ ]
72
+
66
73
  # Is the given class a primitive type as recognized by Grape?
67
74
  #
68
75
  # @param type [Class] type to check
@@ -126,6 +133,15 @@ module Grape
126
133
  SPECIAL.key? type
127
134
  end
128
135
 
136
+ # Is the declared type a supported group type?
137
+ # Currently supported group types are Array, Hash, JSON, and Array[JSON]
138
+ #
139
+ # @param type [Array<Class>,Class] type to check
140
+ # @return [Boolean] +true+ if the type is a supported group type
141
+ def self.group?(type)
142
+ GROUPS.include? type
143
+ end
144
+
129
145
  # A valid custom type must implement a class-level `parse` method, taking
130
146
  # one String argument and returning the parsed value in its correct type.
131
147
  # @param type [Class] type to check
@@ -5,7 +5,7 @@ module Grape
5
5
  def validate!(params)
6
6
  super
7
7
  if scope_requires_params && only_subset_present
8
- fail Grape::Exceptions::Validation, params: all_keys, message_key: :all_or_none
8
+ fail Grape::Exceptions::Validation, params: all_keys, message: message(:all_or_none)
9
9
  end
10
10
  params
11
11
  end
@@ -2,7 +2,7 @@ module Grape
2
2
  module Validations
3
3
  class AllowBlankValidator < Base
4
4
  def validate_param!(attr_name, params)
5
- return if @option || !params.is_a?(Hash)
5
+ return if (options_key?(:value) ? @option[:value] : @option) || !params.is_a?(Hash)
6
6
 
7
7
  value = params[attr_name]
8
8
  value = value.strip if value.respond_to?(:strip)
@@ -23,7 +23,7 @@ module Grape
23
23
 
24
24
  return if value == false || value.present?
25
25
 
26
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :blank
26
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:blank)
27
27
  end
28
28
  end
29
29
  end
@@ -5,7 +5,7 @@ module Grape
5
5
  def validate!(params)
6
6
  super
7
7
  if scope_requires_params && no_exclusive_params_are_present
8
- fail Grape::Exceptions::Validation, params: all_keys, message_key: :at_least_one
8
+ fail Grape::Exceptions::Validation, params: all_keys, message: message(:at_least_one)
9
9
  end
10
10
  params
11
11
  end
@@ -17,6 +17,22 @@ module Grape
17
17
  @scope = scope
18
18
  end
19
19
 
20
+ # Validates a given request.
21
+ # @note This method must be thread-safe.
22
+ # @note Override #validate! unless you need to access the entire request.
23
+ # @param request [Grape::Request] the request currently being handled
24
+ # @raise [Grape::Exceptions::Validation] if validation failed
25
+ # @return [void]
26
+ def validate(request)
27
+ validate!(request.params)
28
+ end
29
+
30
+ # Validates a given parameter hash.
31
+ # @note This method must be thread-safe.
32
+ # @note Override #validate iff you need to access the entire request.
33
+ # @param params [Hash] parameters to validate
34
+ # @raise [Grape::Exceptions::Validation] if validation failed
35
+ # @return [void]
20
36
  def validate!(params)
21
37
  attributes = AttributesIterator.new(self, @scope, params)
22
38
  attributes.each do |resource_params, attr_name|
@@ -39,6 +55,16 @@ module Grape
39
55
  short_name = convert_to_short_name(klass)
40
56
  Validations.register_validator(short_name, klass)
41
57
  end
58
+
59
+ def message(default_key = nil)
60
+ options = instance_variable_get(:@option)
61
+ options_key?(:message) ? options[:message] : default_key
62
+ end
63
+
64
+ def options_key?(key, options = nil)
65
+ options = instance_variable_get(:@option) if options.nil?
66
+ options.respond_to?(:key?) && options.key?(key) && !options[key].nil?
67
+ end
42
68
  end
43
69
  end
44
70
  end
@@ -5,18 +5,31 @@ module Grape
5
5
 
6
6
  module Validations
7
7
  class CoerceValidator < Base
8
+ def initialize(*_args)
9
+ super
10
+ @converter = Types.build_coercer(type, @option[:method])
11
+ end
12
+
8
13
  def validate_param!(attr_name, params)
9
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :coerce unless params.is_a? Hash
14
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce) unless params.is_a? Hash
10
15
  new_value = coerce_value(params[attr_name])
11
16
  if valid_type?(new_value)
12
17
  params[attr_name] = new_value
13
18
  else
14
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :coerce
19
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:coerce)
15
20
  end
16
21
  end
17
22
 
18
23
  private
19
24
 
25
+ # @!attribute [r] converter
26
+ # Object that will be used for parameter coercion and type checking.
27
+ #
28
+ # See {Types.build_coercer}
29
+ #
30
+ # @return [Virtus::Attribute]
31
+ attr_reader :converter
32
+
20
33
  def valid_type?(val)
21
34
  # Special value to denote coercion failure
22
35
  return false if val.instance_of?(Types::InvalidValue)
@@ -47,18 +60,7 @@ module Grape
47
60
  #
48
61
  # @return [Class]
49
62
  def type
50
- @option[:type]
51
- end
52
-
53
- # Create and cache the attribute object
54
- # that will be used for parameter coercion
55
- # and type checking.
56
- #
57
- # See {Types.build_coercer}
58
- #
59
- # @return [Virtus::Attribute]
60
- def converter
61
- @converter ||= Types.build_coercer(type, @option[:method])
63
+ @option[:type].is_a?(Hash) ? @option[:type][:value] : @option[:type]
62
64
  end
63
65
  end
64
66
  end
@@ -15,7 +15,7 @@ module Grape
15
15
 
16
16
  attrs = AttributesIterator.new(self, @scope, params)
17
17
  attrs.each do |resource_params, attr_name|
18
- if resource_params[attr_name].nil?
18
+ if resource_params.is_a?(Hash) && resource_params[attr_name].nil?
19
19
  validate_param!(attr_name, resource_params)
20
20
  end
21
21
  end
@@ -5,11 +5,20 @@ module Grape
5
5
  def validate!(params)
6
6
  super
7
7
  if scope_requires_params && none_of_restricted_params_is_present
8
- fail Grape::Exceptions::Validation, params: all_keys, message_key: :exactly_one
8
+ fail Grape::Exceptions::Validation, params: all_keys, message: message(:exactly_one)
9
9
  end
10
10
  params
11
11
  end
12
12
 
13
+ def message(default_key = nil)
14
+ options = instance_variable_get(:@option)
15
+ if options_key?(:message)
16
+ (options_key?(default_key, options[:message]) ? options[:message][default_key] : options[:message])
17
+ else
18
+ default_key
19
+ end
20
+ end
21
+
13
22
  private
14
23
 
15
24
  def none_of_restricted_params_is_present
@@ -7,7 +7,7 @@ module Grape
7
7
  def validate!(params)
8
8
  super
9
9
  if two_or_more_exclusive_params_are_present
10
- fail Grape::Exceptions::Validation, params: processing_keys_in_common, message_key: :mutual_exclusion
10
+ fail Grape::Exceptions::Validation, params: processing_keys_in_common, message: message(:mutual_exclusion)
11
11
  end
12
12
  params
13
13
  end
@@ -8,7 +8,7 @@ module Grape
8
8
 
9
9
  def validate_param!(attr_name, params)
10
10
  return if params.respond_to?(:key?) && params.key?(attr_name)
11
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
11
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:presence)
12
12
  end
13
13
  end
14
14
  end