grape 3.1.1 → 3.2.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/README.md +76 -161
  4. data/UPGRADING.md +106 -0
  5. data/grape.gemspec +2 -2
  6. data/lib/grape/api/instance.rb +1 -1
  7. data/lib/grape/api.rb +1 -1
  8. data/lib/grape/declared_params_handler.rb +3 -3
  9. data/lib/grape/dsl/declared.rb +1 -1
  10. data/lib/grape/dsl/desc.rb +1 -1
  11. data/lib/grape/dsl/inside_route.rb +9 -9
  12. data/lib/grape/dsl/parameters.rb +14 -14
  13. data/lib/grape/dsl/routing.rb +8 -8
  14. data/lib/grape/endpoint.rb +42 -49
  15. data/lib/grape/error_formatter/base.rb +2 -2
  16. data/lib/grape/exceptions/base.rb +18 -44
  17. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  18. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  19. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  20. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  21. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  22. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  23. data/lib/grape/exceptions/method_not_allowed.rb +1 -1
  24. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  25. data/lib/grape/exceptions/request_error.rb +11 -0
  26. data/lib/grape/exceptions/unknown_auth_strategy.rb +1 -1
  27. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  28. data/lib/grape/exceptions/unknown_params_builder.rb +1 -1
  29. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  30. data/lib/grape/exceptions/validation.rb +7 -4
  31. data/lib/grape/exceptions/validation_errors.rb +13 -7
  32. data/lib/grape/locale/en.yml +0 -5
  33. data/lib/grape/middleware/auth/base.rb +2 -0
  34. data/lib/grape/middleware/base.rb +2 -4
  35. data/lib/grape/middleware/error.rb +2 -2
  36. data/lib/grape/middleware/formatter.rb +1 -1
  37. data/lib/grape/middleware/versioner/accept_version_header.rb +1 -1
  38. data/lib/grape/request.rb +2 -10
  39. data/lib/grape/router/pattern.rb +1 -1
  40. data/lib/grape/router.rb +4 -2
  41. data/lib/grape/util/api_description.rb +1 -1
  42. data/lib/grape/util/deep_freeze.rb +35 -0
  43. data/lib/grape/util/inheritable_setting.rb +1 -1
  44. data/lib/grape/util/media_type.rb +1 -1
  45. data/lib/grape/util/translation.rb +42 -0
  46. data/lib/grape/validations/attributes_iterator.rb +33 -18
  47. data/lib/grape/validations/contract_scope.rb +1 -7
  48. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  49. data/lib/grape/validations/param_scope_tracker.rb +57 -0
  50. data/lib/grape/validations/params_scope.rb +111 -107
  51. data/lib/grape/validations/single_attribute_iterator.rb +2 -2
  52. data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
  53. data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
  54. data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
  55. data/lib/grape/validations/validators/base.rb +95 -18
  56. data/lib/grape/validations/validators/coerce_validator.rb +15 -35
  57. data/lib/grape/validations/validators/contract_scope_validator.rb +10 -8
  58. data/lib/grape/validations/validators/default_validator.rb +12 -18
  59. data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
  60. data/lib/grape/validations/validators/except_values_validator.rb +13 -4
  61. data/lib/grape/validations/validators/length_validator.rb +21 -22
  62. data/lib/grape/validations/validators/multiple_params_base.rb +5 -5
  63. data/lib/grape/validations/validators/mutually_exclusive_validator.rb +3 -1
  64. data/lib/grape/validations/validators/presence_validator.rb +4 -2
  65. data/lib/grape/validations/validators/regexp_validator.rb +8 -10
  66. data/lib/grape/validations/validators/same_as_validator.rb +6 -15
  67. data/lib/grape/validations/validators/values_validator.rb +29 -21
  68. data/lib/grape/version.rb +1 -1
  69. data/lib/grape.rb +18 -1
  70. metadata +11 -13
  71. data/lib/grape/exceptions/conflicting_types.rb +0 -11
  72. data/lib/grape/exceptions/empty_message_body.rb +0 -11
  73. data/lib/grape/exceptions/invalid_parameters.rb +0 -11
  74. data/lib/grape/exceptions/too_deep_parameters.rb +0 -11
  75. data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
  76. data/lib/grape/validations/validator_factory.rb +0 -15
@@ -4,22 +4,27 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class CoerceValidator < Base
7
+ default_message_key :coerce
8
+
7
9
  def initialize(attrs, options, required, scope, opts)
8
10
  super
9
11
 
10
- @converter = if type.is_a?(Grape::Validations::Types::VariantCollectionCoercer)
11
- type
12
- else
13
- Types.build_coercer(type, method: @option[:method])
14
- end
12
+ raw_type = @options[:type]
13
+ type = hash_like?(raw_type) ? raw_type[:value] : raw_type
14
+ @converter =
15
+ if type.is_a?(Grape::Validations::Types::VariantCollectionCoercer)
16
+ type
17
+ else
18
+ Types.build_coercer(type, method: @options[:method])
19
+ end
15
20
  end
16
21
 
17
22
  def validate_param!(attr_name, params)
18
- raise validation_exception(attr_name) unless params.is_a? Hash
23
+ validation_error!(attr_name) unless hash_like?(params)
19
24
 
20
25
  new_value = coerce_value(params[attr_name])
21
26
 
22
- raise validation_exception(attr_name, new_value.message) unless valid_type?(new_value)
27
+ validation_error!(attr_name, new_value.message || @exception_message) if new_value.is_a?(Types::InvalidValue)
23
28
 
24
29
  # Don't assign a value if it is identical. It fixes a problem with Hashie::Mash
25
30
  # which looses wrappers for hashes and arrays after reassigning values
@@ -37,38 +42,13 @@ module Grape
37
42
 
38
43
  private
39
44
 
40
- # @!attribute [r] converter
41
- # Object that will be used for parameter coercion and type checking.
42
- #
43
- # See {Types.build_coercer}
44
- #
45
- # @return [Object]
46
- attr_reader :converter
47
-
48
- def valid_type?(val)
49
- !val.is_a?(Types::InvalidValue)
50
- end
51
-
45
+ # Calls the converter built at definition time.
46
+ # Custom coercers may raise; any StandardError is treated as an invalid value.
52
47
  def coerce_value(val)
53
- converter.call(val)
54
- # Some custom types might fail, so it should be treated as an invalid value
48
+ @converter.call(val)
55
49
  rescue StandardError
56
50
  Types::InvalidValue.new
57
51
  end
58
-
59
- # Type to which the parameter will be coerced.
60
- #
61
- # @return [Class]
62
- def type
63
- @option[:type].is_a?(Hash) ? @option[:type][:value] : @option[:type]
64
- end
65
-
66
- def validation_exception(attr_name, custom_msg = nil)
67
- Grape::Exceptions::Validation.new(
68
- params: [@scope.full_name(attr_name)],
69
- message: custom_msg || message(:coerce)
70
- )
71
- end
72
52
  end
73
53
  end
74
54
  end
@@ -3,12 +3,10 @@
3
3
  module Grape
4
4
  module Validations
5
5
  module Validators
6
- class ContractScopeValidator < Base
7
- attr_reader :schema
8
-
9
- def initialize(_attrs, _options, _required, _scope, opts)
10
- super
11
- @schema = opts.fetch(:schema)
6
+ class ContractScopeValidator
7
+ def initialize(schema:)
8
+ @schema = schema
9
+ freeze
12
10
  end
13
11
 
14
12
  # Validates a given request.
@@ -16,7 +14,7 @@ module Grape
16
14
  # @raise [Grape::Exceptions::ValidationArrayErrors] if validation failed
17
15
  # @return [void]
18
16
  def validate(request)
19
- res = schema.call(request.params)
17
+ res = @schema.call(request.params)
20
18
 
21
19
  if res.success?
22
20
  request.params.deep_merge!(res.to_h)
@@ -26,13 +24,17 @@ module Grape
26
24
  raise Grape::Exceptions::ValidationArrayErrors.new(build_errors_from_messages(res.errors.messages))
27
25
  end
28
26
 
27
+ def fail_fast?
28
+ false
29
+ end
30
+
29
31
  private
30
32
 
31
33
  def build_errors_from_messages(messages)
32
34
  messages.map do |message|
33
35
  full_name = message.path.first.to_s
34
36
  full_name << "[#{message.path[1..].join('][')}]" if message.path.size > 1
35
- Grape::Exceptions::Validation.new(params: [full_name], message: message.text)
37
+ Grape::Exceptions::Validation.new(params: full_name, message: message.text)
36
38
  end
37
39
  end
38
40
  end
@@ -4,31 +4,25 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class DefaultValidator < Base
7
- def initialize(attrs, options, required, scope, opts = {})
8
- @default = options
7
+ def initialize(attrs, options, required, scope, opts)
9
8
  super
10
- end
11
-
12
- def validate_param!(attr_name, params)
13
- params[attr_name] = if @default.is_a? Proc
14
- if @default.parameters.empty?
15
- @default.call
16
- else
17
- @default.call(params)
18
- end
19
- elsif @default.frozen? || !@default.duplicable?
20
- @default
21
- else
22
- @default.dup
23
- end
9
+ # !important, lazy call at runtime
10
+ @default_call =
11
+ if @options.is_a?(Proc)
12
+ @options.arity.zero? ? proc { @options.call } : @options
13
+ elsif @options.duplicable?
14
+ proc { @options.dup }
15
+ else
16
+ proc { @options }
17
+ end
24
18
  end
25
19
 
26
20
  def validate!(params)
27
- attrs = SingleAttributeIterator.new(self, @scope, params)
21
+ attrs = SingleAttributeIterator.new(@attrs, @scope, params)
28
22
  attrs.each do |resource_params, attr_name|
29
23
  next unless @scope.meets_dependency?(resource_params, params)
30
24
 
31
- validate_param!(attr_name, resource_params) if resource_params.is_a?(Hash) && resource_params[attr_name].nil?
25
+ resource_params[attr_name] = @default_call.call(resource_params) if hash_like?(resource_params) && resource_params[attr_name].nil?
32
26
  end
33
27
  end
34
28
  end
@@ -4,12 +4,19 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class ExactlyOneOfValidator < MultipleParamsBase
7
+ def initialize(attrs, options, required, scope, opts)
8
+ super
9
+ @exactly_one_exception_message = message(:exactly_one)
10
+ @mutual_exclusion_exception_message = message(:mutual_exclusion)
11
+ end
12
+
7
13
  def validate_params!(params)
8
- keys = keys_in_common(params)
14
+ known_keys = all_keys
15
+ keys = keys_in_common(params, known_keys)
9
16
  return if keys.length == 1
10
- raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.empty?
11
17
 
12
- raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
18
+ validation_error!(known_keys, @exactly_one_exception_message) if keys.empty?
19
+ validation_error!(keys, @mutual_exclusion_exception_message)
13
20
  end
14
21
  end
15
22
  end
@@ -4,19 +4,28 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class ExceptValuesValidator < Base
7
+ default_message_key :except_values
8
+
7
9
  def initialize(attrs, options, required, scope, opts)
8
- @except = options.is_a?(Hash) ? options[:value] : options
9
10
  super
11
+ except = option_value
12
+ raise ArgumentError, 'except_values Proc must have arity of zero (use values: with a one-arity predicate for per-element checks)' if except.is_a?(Proc) && !except.arity.zero?
13
+
14
+ # Zero-arity procs (e.g. -> { User.pluck(:role) }) must be called per-request,
15
+ # not at definition time, so they are wrapped in a lambda to defer execution.
16
+ @excepts_call = except.is_a?(Proc) ? except : -> { except }
10
17
  end
11
18
 
12
19
  def validate_param!(attr_name, params)
13
- return unless params.respond_to?(:key?) && params.key?(attr_name)
20
+ return unless hash_like?(params) && params.key?(attr_name)
14
21
 
15
- excepts = @except.is_a?(Proc) ? @except.call : @except
22
+ excepts = @excepts_call.call
16
23
  return if excepts.nil?
17
24
 
18
25
  param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
19
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:except_values)) if param_array.any? { |param| excepts.include?(param) }
26
+ return if param_array.none? { |param| excepts.include?(param) }
27
+
28
+ validation_error!(attr_name)
20
29
  end
21
30
  end
22
31
  end
@@ -5,19 +5,16 @@ module Grape
5
5
  module Validators
6
6
  class LengthValidator < Base
7
7
  def initialize(attrs, options, required, scope, opts)
8
- @min = options[:min]
9
- @max = options[:max]
10
- @is = options[:is]
11
-
12
8
  super
13
9
 
14
- raise ArgumentError, 'min must be an integer greater than or equal to zero' if !@min.nil? && (!@min.is_a?(Integer) || @min.negative?)
15
- raise ArgumentError, 'max must be an integer greater than or equal to zero' if !@max.nil? && (!@max.is_a?(Integer) || @max.negative?)
16
- raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if !@min.nil? && !@max.nil? && @min > @max
10
+ @min, @max, @is = @options.values_at(:min, :max, :is)
11
+ validate_boundary!(:min, @min)
12
+ validate_boundary!(:max, @max)
13
+ raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if @min && @max && @min > @max
17
14
 
18
15
  return if @is.nil?
19
- raise ArgumentError, 'is must be an integer greater than zero' if !@is.is_a?(Integer) || !@is.positive?
20
- raise ArgumentError, 'is cannot be combined with min or max' if !@min.nil? || !@max.nil?
16
+ raise ArgumentError, 'is must be an integer greater than zero' unless @is.is_a?(Integer) && @is.positive?
17
+ raise ArgumentError, 'is cannot be combined with min or max' unless @min.nil? && @max.nil?
21
18
  end
22
19
 
23
20
  def validate_param!(attr_name, params)
@@ -27,21 +24,23 @@ module Grape
27
24
 
28
25
  return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)
29
26
 
30
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: build_message)
27
+ validation_error!(attr_name, message do
28
+ if @min && @max
29
+ translate(:length, min: @min, max: @max)
30
+ elsif @min
31
+ translate(:length_min, min: @min)
32
+ elsif @max
33
+ translate(:length_max, max: @max)
34
+ else
35
+ translate(:length_is, is: @is)
36
+ end
37
+ end)
31
38
  end
32
39
 
33
- def build_message
34
- if options_key?(:message)
35
- @option[:message]
36
- elsif @min && @max
37
- format I18n.t(:length, scope: 'grape.errors.messages'), min: @min, max: @max
38
- elsif @min
39
- format I18n.t(:length_min, scope: 'grape.errors.messages'), min: @min
40
- elsif @max
41
- format I18n.t(:length_max, scope: 'grape.errors.messages'), max: @max
42
- else
43
- format I18n.t(:length_is, scope: 'grape.errors.messages'), is: @is
44
- end
40
+ private
41
+
42
+ def validate_boundary!(name, val)
43
+ raise ArgumentError, "#{name} must be an integer greater than or equal to zero" if !val.nil? && (!val.is_a?(Integer) || val.negative?)
45
44
  end
46
45
  end
47
46
  end
@@ -5,7 +5,7 @@ module Grape
5
5
  module Validators
6
6
  class MultipleParamsBase < Base
7
7
  def validate!(params)
8
- attributes = MultipleAttributesIterator.new(self, @scope, params)
8
+ attributes = MultipleAttributesIterator.new(@attrs, @scope, params)
9
9
  array_errors = []
10
10
 
11
11
  attributes.each do |resource_params|
@@ -19,14 +19,14 @@ module Grape
19
19
 
20
20
  private
21
21
 
22
- def keys_in_common(resource_params)
23
- return [] unless resource_params.is_a?(Hash)
22
+ def keys_in_common(resource_params, known_keys = all_keys)
23
+ return [] unless hash_like?(resource_params)
24
24
 
25
- all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
25
+ known_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
26
26
  end
27
27
 
28
28
  def all_keys
29
- attrs.map { |attr| @scope.full_name(attr) }
29
+ @attrs.map { |attr| @scope.full_name(attr) }
30
30
  end
31
31
  end
32
32
  end
@@ -4,11 +4,13 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class MutuallyExclusiveValidator < MultipleParamsBase
7
+ default_message_key :mutual_exclusion
8
+
7
9
  def validate_params!(params)
8
10
  keys = keys_in_common(params)
9
11
  return if keys.length <= 1
10
12
 
11
- raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
13
+ validation_error!(keys)
12
14
  end
13
15
  end
14
16
  end
@@ -4,10 +4,12 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class PresenceValidator < Base
7
+ default_message_key :presence
8
+
7
9
  def validate_param!(attr_name, params)
8
- return if params.respond_to?(:key?) && params.key?(attr_name)
10
+ return if hash_like?(params) && params.key?(attr_name)
9
11
 
10
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
12
+ validation_error!(attr_name)
11
13
  end
12
14
  end
13
15
  end
@@ -4,21 +4,19 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class RegexpValidator < Base
7
- def validate_param!(attr_name, params)
8
- return unless params.respond_to?(:key) && params.key?(attr_name)
9
-
10
- value = options_key?(:value) ? @option[:value] : @option
11
- return if Array.wrap(params[attr_name]).all? { |param| param.nil? || scrub(param.to_s).match?(value) }
7
+ default_message_key :regexp
12
8
 
13
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
9
+ def initialize(attrs, options, required, scope, opts)
10
+ super
11
+ @value = option_value
14
12
  end
15
13
 
16
- private
14
+ def validate_param!(attr_name, params)
15
+ return unless hash_like?(params) && params.key?(attr_name)
17
16
 
18
- def scrub(param)
19
- return param if param.valid_encoding?
17
+ return if Array.wrap(params[attr_name]).all? { |param| param.nil? || scrub(param.to_s).match?(@value) }
20
18
 
21
- param.scrub
19
+ validation_error!(attr_name)
22
20
  end
23
21
  end
24
22
  end
@@ -4,24 +4,15 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class SameAsValidator < Base
7
- def validate_param!(attr_name, params)
8
- confirmation = options_key?(:value) ? @option[:value] : @option
9
- return if params[attr_name] == params[confirmation]
10
-
11
- raise Grape::Exceptions::Validation.new(
12
- params: [@scope.full_name(attr_name)],
13
- message: build_message
14
- )
7
+ def initialize(attrs, options, required, scope, opts)
8
+ super
9
+ @value = option_value
15
10
  end
16
11
 
17
- private
12
+ def validate_param!(attr_name, params)
13
+ return if params[attr_name] == params[@value]
18
14
 
19
- def build_message
20
- if options_key?(:message)
21
- @option[:message]
22
- else
23
- format I18n.t(:same_as, scope: 'grape.errors.messages'), parameter: @option
24
- end
15
+ validation_error!(attr_name, message { translate(:same_as, parameter: @value) })
25
16
  end
26
17
  end
27
18
  end
@@ -4,45 +4,53 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class ValuesValidator < Base
7
+ default_message_key :values
8
+
7
9
  def initialize(attrs, options, required, scope, opts)
8
- @values = options.is_a?(Hash) ? options[:value] : options
9
10
  super
11
+ values = option_value
12
+
13
+ # Zero-arity procs return a collection per-request (e.g. DB-backed lists).
14
+ # Non-zero-arity procs are per-element predicates, called directly at validation time.
15
+ # Non-Proc values are wrapped in a zero-arity lambda for a uniform call interface.
16
+ if values.is_a?(Proc)
17
+ @values_call = values
18
+ @values_is_predicate = !values.arity.zero?
19
+ else
20
+ @values_call = -> { values }
21
+ @values_is_predicate = false
22
+ end
10
23
  end
11
24
 
12
25
  def validate_param!(attr_name, params)
13
- return unless params.is_a?(Hash)
26
+ return unless hash_like?(params)
14
27
 
15
- val = params[attr_name]
28
+ val = scrub(params[attr_name])
16
29
 
17
30
  return if val.nil? && !required_for_root_scope?
18
-
19
- val = val.scrub if val.respond_to?(:valid_encoding?) && !val.valid_encoding?
20
-
21
- # don't forget that +false.blank?+ is true
22
31
  return if val != false && val.blank? && @allow_blank
23
-
24
32
  return if check_values?(val, attr_name)
25
33
 
26
- raise Grape::Exceptions::Validation.new(
27
- params: [@scope.full_name(attr_name)],
28
- message: message(:values)
29
- )
34
+ validation_error!(attr_name)
30
35
  end
31
36
 
32
37
  private
33
38
 
34
39
  def check_values?(val, attr_name)
35
- values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
36
- return true if values.nil?
37
-
38
40
  param_array = val.nil? ? [nil] : Array.wrap(val)
39
- return param_array.all? { |param| values.include?(param) } unless values.is_a?(Proc)
40
41
 
41
- begin
42
- param_array.all? { |param| values.call(param) }
43
- rescue StandardError => e
44
- warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
45
- false
42
+ if @values_is_predicate
43
+ begin
44
+ param_array.all? { |param| @values_call.call(param) }
45
+ rescue StandardError => e
46
+ warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
47
+ false
48
+ end
49
+ else
50
+ values = @values_call.call
51
+ return true if values.nil?
52
+
53
+ param_array.all? { |param| values.include?(param) }
46
54
  end
47
55
  end
48
56
 
data/lib/grape/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Grape
4
4
  # The current version of Grape.
5
- VERSION = '3.1.1'
5
+ VERSION = '3.2.0'
6
6
  end
data/lib/grape.rb CHANGED
@@ -33,7 +33,6 @@ require 'rack'
33
33
  require 'rack/auth/basic'
34
34
  require 'rack/builder'
35
35
  require 'rack/head'
36
- require 'set'
37
36
  require 'singleton'
38
37
  require 'zeitwerk'
39
38
 
@@ -64,6 +63,24 @@ module Grape
64
63
  Rack::OPTIONS
65
64
  ].freeze
66
65
 
66
+ # Rack errors that should be rescued and wrapped as Grape::Exceptions::RequestError.
67
+ # Rack 3.1.0 introduced Rack::BadRequest as a marker module included by all bad request
68
+ # exception classes, allowing a single rescue entry to cover them all.
69
+ # Before, these errors are raised as individual exception classes.
70
+ RACK_ERRORS =
71
+ if Gem::Version.new(Rack.release) >= Gem::Version.new('3.1.0')
72
+ [EOFError, Rack::BadRequest]
73
+ else
74
+ [
75
+ EOFError,
76
+ Rack::Multipart::MultipartPartLimitError,
77
+ Rack::Multipart::MultipartTotalPartLimitError,
78
+ Rack::Utils::ParameterTypeError,
79
+ Rack::Utils::InvalidParameterError,
80
+ Rack::QueryParser::ParamsTooDeepError
81
+ ]
82
+ end.freeze
83
+
67
84
  def self.deprecator
68
85
  @deprecator ||= ActiveSupport::Deprecation.new('2.0', 'Grape')
69
86
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '7.1'
18
+ version: '7.2'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '7.1'
25
+ version: '7.2'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: dry-configurable
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -136,13 +136,10 @@ files:
136
136
  - lib/grape/error_formatter/txt.rb
137
137
  - lib/grape/error_formatter/xml.rb
138
138
  - lib/grape/exceptions/base.rb
139
- - lib/grape/exceptions/conflicting_types.rb
140
- - lib/grape/exceptions/empty_message_body.rb
141
139
  - lib/grape/exceptions/incompatible_option_values.rb
142
140
  - lib/grape/exceptions/invalid_accept_header.rb
143
141
  - lib/grape/exceptions/invalid_formatter.rb
144
142
  - lib/grape/exceptions/invalid_message_body.rb
145
- - lib/grape/exceptions/invalid_parameters.rb
146
143
  - lib/grape/exceptions/invalid_response.rb
147
144
  - lib/grape/exceptions/invalid_version_header.rb
148
145
  - lib/grape/exceptions/invalid_versioner_option.rb
@@ -151,8 +148,7 @@ files:
151
148
  - lib/grape/exceptions/missing_group_type.rb
152
149
  - lib/grape/exceptions/missing_mime_type.rb
153
150
  - lib/grape/exceptions/missing_vendor_option.rb
154
- - lib/grape/exceptions/too_deep_parameters.rb
155
- - lib/grape/exceptions/too_many_multipart_files.rb
151
+ - lib/grape/exceptions/request_error.rb
156
152
  - lib/grape/exceptions/unknown_auth_strategy.rb
157
153
  - lib/grape/exceptions/unknown_parameter.rb
158
154
  - lib/grape/exceptions/unknown_params_builder.rb
@@ -210,6 +206,7 @@ files:
210
206
  - lib/grape/util/api_description.rb
211
207
  - lib/grape/util/base_inheritable.rb
212
208
  - lib/grape/util/cache.rb
209
+ - lib/grape/util/deep_freeze.rb
213
210
  - lib/grape/util/endpoint_configuration.rb
214
211
  - lib/grape/util/header.rb
215
212
  - lib/grape/util/inheritable_setting.rb
@@ -223,10 +220,12 @@ files:
223
220
  - lib/grape/util/registry.rb
224
221
  - lib/grape/util/reverse_stackable_values.rb
225
222
  - lib/grape/util/stackable_values.rb
223
+ - lib/grape/util/translation.rb
226
224
  - lib/grape/validations.rb
227
225
  - lib/grape/validations/attributes_iterator.rb
228
226
  - lib/grape/validations/contract_scope.rb
229
227
  - lib/grape/validations/multiple_attributes_iterator.rb
228
+ - lib/grape/validations/param_scope_tracker.rb
230
229
  - lib/grape/validations/params_documentation.rb
231
230
  - lib/grape/validations/params_scope.rb
232
231
  - lib/grape/validations/single_attribute_iterator.rb
@@ -242,7 +241,6 @@ files:
242
241
  - lib/grape/validations/types/primitive_coercer.rb
243
242
  - lib/grape/validations/types/set_coercer.rb
244
243
  - lib/grape/validations/types/variant_collection_coercer.rb
245
- - lib/grape/validations/validator_factory.rb
246
244
  - lib/grape/validations/validators/all_or_none_of_validator.rb
247
245
  - lib/grape/validations/validators/allow_blank_validator.rb
248
246
  - lib/grape/validations/validators/as_validator.rb
@@ -267,9 +265,9 @@ licenses:
267
265
  - MIT
268
266
  metadata:
269
267
  bug_tracker_uri: https://github.com/ruby-grape/grape/issues
270
- changelog_uri: https://github.com/ruby-grape/grape/blob/v3.1.1/CHANGELOG.md
271
- documentation_uri: https://www.rubydoc.info/gems/grape/3.1.1
272
- source_code_uri: https://github.com/ruby-grape/grape/tree/v3.1.1
268
+ changelog_uri: https://github.com/ruby-grape/grape/blob/v3.2.0/CHANGELOG.md
269
+ documentation_uri: https://www.rubydoc.info/gems/grape/3.2.0
270
+ source_code_uri: https://github.com/ruby-grape/grape/tree/v3.2.0
273
271
  rubygems_mfa_required: 'true'
274
272
  rdoc_options: []
275
273
  require_paths:
@@ -278,7 +276,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
278
276
  requirements:
279
277
  - - ">="
280
278
  - !ruby/object:Gem::Version
281
- version: '3.1'
279
+ version: '3.2'
282
280
  required_rubygems_version: !ruby/object:Gem::Requirement
283
281
  requirements:
284
282
  - - ">="
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Exceptions
5
- class ConflictingTypes < Base
6
- def initialize
7
- super(message: compose_message(:conflicting_types), status: 400)
8
- end
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Exceptions
5
- class EmptyMessageBody < Base
6
- def initialize(body_format)
7
- super(message: compose_message(:empty_message_body, body_format: body_format), status: 400)
8
- end
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Exceptions
5
- class InvalidParameters < Base
6
- def initialize
7
- super(message: compose_message(:invalid_parameters), status: 400)
8
- end
9
- end
10
- end
11
- end