grape 1.5.2 → 1.7.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 +75 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +152 -21
- data/UPGRADING.md +86 -2
- data/grape.gemspec +5 -5
- data/lib/grape/api/instance.rb +14 -18
- data/lib/grape/api.rb +18 -13
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dry_types.rb +12 -0
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/callbacks.rb +0 -2
- data/lib/grape/dsl/configuration.rb +0 -2
- data/lib/grape/dsl/desc.rb +2 -19
- data/lib/grape/dsl/headers.rb +5 -2
- data/lib/grape/dsl/helpers.rb +7 -7
- data/lib/grape/dsl/inside_route.rb +43 -30
- data/lib/grape/dsl/middleware.rb +4 -6
- data/lib/grape/dsl/parameters.rb +8 -10
- data/lib/grape/dsl/request_response.rb +9 -8
- data/lib/grape/dsl/routing.rb +6 -4
- data/lib/grape/dsl/settings.rb +5 -7
- data/lib/grape/dsl/validations.rb +0 -15
- data/lib/grape/endpoint.rb +21 -36
- data/lib/grape/error_formatter/json.rb +9 -7
- data/lib/grape/error_formatter/xml.rb +2 -6
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/missing_group_type.rb +8 -1
- data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
- data/lib/grape/exceptions/validation.rb +1 -6
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -1
- data/lib/grape/formatter/xml.rb +1 -0
- data/lib/grape/locale/en.yml +9 -8
- data/lib/grape/middleware/auth/dsl.rb +7 -2
- data/lib/grape/middleware/base.rb +3 -1
- data/lib/grape/middleware/error.rb +2 -2
- data/lib/grape/middleware/formatter.rb +4 -4
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
- data/lib/grape/middleware/versioner/header.rb +6 -4
- data/lib/grape/middleware/versioner/param.rb +1 -0
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
- data/lib/grape/middleware/versioner/path.rb +2 -0
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/parser/xml.rb +1 -1
- data/lib/grape/path.rb +1 -0
- data/lib/grape/request.rb +5 -0
- data/lib/grape/router/pattern.rb +1 -1
- data/lib/grape/router/route.rb +2 -2
- data/lib/grape/router.rb +6 -0
- data/lib/grape/util/inheritable_setting.rb +1 -3
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_value.rb +3 -2
- data/lib/grape/util/strict_hash_configuration.rb +1 -1
- data/lib/grape/validations/attributes_doc.rb +58 -0
- data/lib/grape/validations/params_scope.rb +137 -78
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
- data/lib/grape/validations/types/json.rb +2 -1
- data/lib/grape/validations/types/primitive_coercer.rb +16 -8
- data/lib/grape/validations/types/set_coercer.rb +0 -2
- data/lib/grape/validations/types.rb +98 -30
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +82 -70
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/default_validator.rb +51 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +88 -0
- data/lib/grape/validations.rb +16 -6
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +70 -29
- data/spec/grape/api/custom_validations_spec.rb +116 -45
- data/spec/grape/api/deeply_included_options_spec.rb +3 -5
- data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
- data/spec/grape/api/documentation_spec.rb +59 -0
- data/spec/grape/api/inherited_helpers_spec.rb +0 -2
- data/spec/grape/api/instance_spec.rb +0 -1
- data/spec/grape/api/invalid_format_spec.rb +2 -2
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/nested_helpers_spec.rb +0 -2
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/parameters_modification_spec.rb +0 -2
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
- data/spec/grape/api/recognize_path_spec.rb +1 -3
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
- data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
- data/spec/grape/api/shared_helpers_spec.rb +0 -2
- data/spec/grape/api_remount_spec.rb +16 -16
- data/spec/grape/api_spec.rb +527 -224
- data/spec/grape/config_spec.rb +0 -2
- data/spec/grape/dsl/callbacks_spec.rb +2 -3
- data/spec/grape/dsl/configuration_spec.rb +0 -2
- data/spec/grape/dsl/desc_spec.rb +0 -2
- data/spec/grape/dsl/headers_spec.rb +39 -11
- data/spec/grape/dsl/helpers_spec.rb +3 -4
- data/spec/grape/dsl/inside_route_spec.rb +16 -16
- data/spec/grape/dsl/logger_spec.rb +15 -19
- data/spec/grape/dsl/middleware_spec.rb +2 -3
- data/spec/grape/dsl/parameters_spec.rb +2 -2
- data/spec/grape/dsl/request_response_spec.rb +7 -8
- data/spec/grape/dsl/routing_spec.rb +11 -10
- data/spec/grape/dsl/settings_spec.rb +0 -2
- data/spec/grape/dsl/validations_spec.rb +0 -17
- data/spec/grape/endpoint/declared_spec.rb +261 -16
- data/spec/grape/endpoint_spec.rb +98 -57
- data/spec/grape/entity_spec.rb +22 -23
- data/spec/grape/exceptions/base_spec.rb +16 -2
- data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
- data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
- data/spec/grape/exceptions/missing_option_spec.rb +1 -3
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
- data/spec/grape/exceptions/validation_spec.rb +5 -5
- data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
- data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
- data/spec/grape/integration/rack_spec.rb +0 -2
- data/spec/grape/loading_spec.rb +8 -10
- data/spec/grape/middleware/auth/base_spec.rb +0 -1
- data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
- data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
- data/spec/grape/middleware/base_spec.rb +24 -17
- data/spec/grape/middleware/error_spec.rb +8 -3
- data/spec/grape/middleware/exception_spec.rb +111 -163
- data/spec/grape/middleware/formatter_spec.rb +27 -8
- data/spec/grape/middleware/globals_spec.rb +7 -6
- data/spec/grape/middleware/stack_spec.rb +14 -14
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
- data/spec/grape/middleware/versioner/header_spec.rb +30 -15
- data/spec/grape/middleware/versioner/param_spec.rb +7 -3
- data/spec/grape/middleware/versioner/path_spec.rb +5 -3
- data/spec/grape/middleware/versioner_spec.rb +1 -3
- data/spec/grape/named_api_spec.rb +0 -2
- data/spec/grape/parser_spec.rb +4 -2
- data/spec/grape/path_spec.rb +52 -54
- data/spec/grape/presenters/presenter_spec.rb +7 -8
- data/spec/grape/request_spec.rb +6 -6
- data/spec/grape/util/inheritable_setting_spec.rb +7 -8
- data/spec/grape/util/inheritable_values_spec.rb +3 -3
- data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
- data/spec/grape/util/stackable_values_spec.rb +7 -6
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
- data/spec/grape/validations/attributes_doc_spec.rb +153 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
- data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
- data/spec/grape/validations/params_scope_spec.rb +361 -96
- data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
- data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
- data/spec/grape/validations/types_spec.rb +36 -10
- data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
- data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
- data/spec/grape/validations/validators/coerce_spec.rb +99 -24
- data/spec/grape/validations/validators/default_spec.rb +72 -80
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
- data/spec/grape/validations/validators/except_values_spec.rb +3 -5
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
- data/spec/grape/validations/validators/presence_spec.rb +16 -3
- data/spec/grape/validations/validators/regexp_spec.rb +25 -33
- data/spec/grape/validations/validators/same_as_spec.rb +14 -22
- data/spec/grape/validations/validators/values_spec.rb +182 -179
- data/spec/grape/validations_spec.rb +149 -80
- data/spec/integration/eager_load/eager_load_spec.rb +2 -2
- data/spec/integration/multi_json/json_spec.rb +1 -3
- data/spec/integration/multi_xml/xml_spec.rb +1 -3
- data/spec/shared/versioning_examples.rb +12 -9
- data/spec/spec_helper.rb +21 -6
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- metadata +125 -115
- data/lib/grape/validations/validators/all_or_none.rb +0 -15
- data/lib/grape/validations/validators/allow_blank.rb +0 -18
- data/lib/grape/validations/validators/as.rb +0 -16
- data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
- data/lib/grape/validations/validators/coerce.rb +0 -91
- data/lib/grape/validations/validators/default.rb +0 -48
- data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
- data/lib/grape/validations/validators/except_values.rb +0 -22
- data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
- data/lib/grape/validations/validators/presence.rb +0 -12
- data/lib/grape/validations/validators/regexp.rb +0 -13
- data/lib/grape/validations/validators/same_as.rb +0 -26
- data/lib/grape/validations/validators/values.rb +0 -83
- data/spec/support/eager_load.rb +0 -19
@@ -2,32 +2,36 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Validations
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
module Validators
|
6
|
+
class MultipleParamsBase < Base
|
7
|
+
def validate!(params)
|
8
|
+
attributes = MultipleAttributesIterator.new(self, @scope, params)
|
9
|
+
array_errors = []
|
10
|
+
|
11
|
+
attributes.each do |resource_params, skip_value|
|
12
|
+
next if skip_value
|
13
|
+
|
14
|
+
begin
|
15
|
+
validate_params!(resource_params)
|
16
|
+
rescue Grape::Exceptions::Validation => e
|
17
|
+
array_errors << e
|
18
|
+
end
|
16
19
|
end
|
20
|
+
|
21
|
+
raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
|
17
22
|
end
|
18
23
|
|
19
|
-
|
20
|
-
end
|
24
|
+
private
|
21
25
|
|
22
|
-
|
26
|
+
def keys_in_common(resource_params)
|
27
|
+
return [] unless resource_params.is_a?(Hash)
|
23
28
|
|
24
|
-
|
25
|
-
|
26
|
-
all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
|
27
|
-
end
|
29
|
+
all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
|
30
|
+
end
|
28
31
|
|
29
|
-
|
30
|
-
|
32
|
+
def all_keys
|
33
|
+
attrs.map { |attr| @scope.full_name(attr) }
|
34
|
+
end
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class MutualExclusionValidator < MultipleParamsBase
|
7
|
+
def validate_params!(params)
|
8
|
+
keys = keys_in_common(params)
|
9
|
+
return if keys.length <= 1
|
10
|
+
|
11
|
+
raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class PresenceValidator < Base
|
7
|
+
def validate_param!(attr_name, params)
|
8
|
+
return if params.respond_to?(:key?) && params.key?(attr_name)
|
9
|
+
|
10
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class RegexpValidator < Base
|
7
|
+
def validate_param!(attr_name, params)
|
8
|
+
return unless params.respond_to?(:key?) && params.key?(attr_name)
|
9
|
+
return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
|
10
|
+
|
11
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
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
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
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
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module Validations
|
5
|
+
module Validators
|
6
|
+
class ValuesValidator < Base
|
7
|
+
def initialize(attrs, options, required, scope, **opts)
|
8
|
+
if options.is_a?(Hash)
|
9
|
+
@excepts = options[:except]
|
10
|
+
@values = options[:value]
|
11
|
+
@proc = options[:proc]
|
12
|
+
|
13
|
+
warn '[DEPRECATION] The values validator except option is deprecated. ' \
|
14
|
+
'Use the except validator instead.' if @excepts
|
15
|
+
|
16
|
+
raise ArgumentError, 'proc must be a Proc' if @proc && !@proc.is_a?(Proc)
|
17
|
+
|
18
|
+
warn '[DEPRECATION] The values validator proc option is deprecated. ' \
|
19
|
+
'The lambda expression can now be assigned directly to values.' if @proc
|
20
|
+
else
|
21
|
+
@excepts = nil
|
22
|
+
@values = nil
|
23
|
+
@proc = nil
|
24
|
+
@values = options
|
25
|
+
end
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_param!(attr_name, params)
|
30
|
+
return unless params.is_a?(Hash)
|
31
|
+
|
32
|
+
val = params[attr_name]
|
33
|
+
|
34
|
+
return if val.nil? && !required_for_root_scope?
|
35
|
+
|
36
|
+
# don't forget that +false.blank?+ is true
|
37
|
+
return if val != false && val.blank? && @allow_blank
|
38
|
+
|
39
|
+
param_array = val.nil? ? [nil] : Array.wrap(val)
|
40
|
+
|
41
|
+
raise validation_exception(attr_name, except_message) \
|
42
|
+
unless check_excepts(param_array)
|
43
|
+
|
44
|
+
raise validation_exception(attr_name, message(:values)) \
|
45
|
+
unless check_values(param_array, attr_name)
|
46
|
+
|
47
|
+
raise validation_exception(attr_name, message(:values)) \
|
48
|
+
if @proc && !param_array.all? { |param| @proc.call(param) }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def check_values(param_array, attr_name)
|
54
|
+
values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
|
55
|
+
return true if values.nil?
|
56
|
+
|
57
|
+
begin
|
58
|
+
return param_array.all? { |param| values.call(param) } if values.is_a? Proc
|
59
|
+
rescue StandardError => e
|
60
|
+
warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
param_array.all? { |param| values.include?(param) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def check_excepts(param_array)
|
67
|
+
excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
|
68
|
+
return true if excepts.nil?
|
69
|
+
|
70
|
+
param_array.none? { |param| excepts.include?(param) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def except_message
|
74
|
+
options = instance_variable_get(:@option)
|
75
|
+
options_key?(:except_message) ? options[:except_message] : message(:except_values)
|
76
|
+
end
|
77
|
+
|
78
|
+
def required_for_root_scope?
|
79
|
+
@required && @scope.root?
|
80
|
+
end
|
81
|
+
|
82
|
+
def validation_exception(attr_name, message)
|
83
|
+
Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/grape/validations.rb
CHANGED
@@ -3,22 +3,32 @@
|
|
3
3
|
module Grape
|
4
4
|
# Registry to store and locate known Validators.
|
5
5
|
module Validations
|
6
|
-
|
7
|
-
attr_accessor :validators
|
8
|
-
end
|
6
|
+
module_function
|
9
7
|
|
10
|
-
|
8
|
+
def validators
|
9
|
+
@validators ||= {}
|
10
|
+
end
|
11
11
|
|
12
12
|
# Register a new validator, so it can be used to validate parameters.
|
13
13
|
# @param short_name [String] all lower-case, no spaces
|
14
14
|
# @param klass [Class] the validator class. Should inherit from
|
15
15
|
# Validations::Base.
|
16
|
-
def
|
16
|
+
def register_validator(short_name, klass)
|
17
17
|
validators[short_name] = klass
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def deregister_validator(short_name)
|
21
21
|
validators.delete(short_name)
|
22
22
|
end
|
23
|
+
|
24
|
+
# Find a validator and if not found will try to load it
|
25
|
+
def require_validator(short_name)
|
26
|
+
str_name = short_name.to_s
|
27
|
+
validators.fetch(str_name) do
|
28
|
+
Grape::Validations::Validators.const_get("#{str_name.camelize}Validator")
|
29
|
+
end
|
30
|
+
rescue NameError
|
31
|
+
raise Grape::Exceptions::UnknownValidator.new(short_name)
|
32
|
+
end
|
23
33
|
end
|
24
34
|
end
|
data/lib/grape/version.rb
CHANGED
data/lib/grape.rb
CHANGED
@@ -7,22 +7,27 @@ require 'rack/accept'
|
|
7
7
|
require 'rack/auth/basic'
|
8
8
|
require 'rack/auth/digest/md5'
|
9
9
|
require 'set'
|
10
|
+
require 'bigdecimal'
|
11
|
+
require 'date'
|
12
|
+
require 'active_support'
|
13
|
+
require 'active_support/concern'
|
10
14
|
require 'active_support/version'
|
11
|
-
require 'active_support/
|
12
|
-
require 'active_support/core_ext/
|
15
|
+
require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6
|
16
|
+
require 'active_support/core_ext/array/conversions'
|
13
17
|
require 'active_support/core_ext/array/extract_options'
|
14
18
|
require 'active_support/core_ext/array/wrap'
|
15
|
-
require 'active_support/core_ext/
|
19
|
+
require 'active_support/core_ext/hash/conversions'
|
16
20
|
require 'active_support/core_ext/hash/deep_merge'
|
17
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
18
21
|
require 'active_support/core_ext/hash/except'
|
22
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
23
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
19
24
|
require 'active_support/core_ext/hash/slice'
|
20
|
-
require 'active_support/core_ext/
|
25
|
+
require 'active_support/core_ext/object/blank'
|
21
26
|
require 'active_support/dependencies/autoload'
|
22
27
|
require 'active_support/notifications'
|
23
28
|
require 'i18n'
|
24
29
|
|
25
|
-
I18n.load_path << File.expand_path('
|
30
|
+
I18n.load_path << File.expand_path('grape/locale/en.yml', __dir__)
|
26
31
|
|
27
32
|
module Grape
|
28
33
|
extend ::ActiveSupport::Autoload
|
@@ -43,6 +48,7 @@ module Grape
|
|
43
48
|
autoload :Env, 'grape/util/env'
|
44
49
|
autoload :Json, 'grape/util/json'
|
45
50
|
autoload :Xml, 'grape/util/xml'
|
51
|
+
autoload :DryTypes
|
46
52
|
end
|
47
53
|
|
48
54
|
module Http
|
@@ -69,13 +75,17 @@ module Grape
|
|
69
75
|
autoload :UnknownParameter
|
70
76
|
autoload :InvalidWithOptionForRepresent
|
71
77
|
autoload :IncompatibleOptionValues
|
72
|
-
autoload :
|
73
|
-
autoload :
|
78
|
+
autoload :MissingGroupType
|
79
|
+
autoload :UnsupportedGroupType
|
74
80
|
autoload :InvalidMessageBody
|
75
81
|
autoload :InvalidAcceptHeader
|
76
82
|
autoload :InvalidVersionHeader
|
77
83
|
autoload :MethodNotAllowed
|
78
84
|
autoload :InvalidResponse
|
85
|
+
autoload :EmptyMessageBody
|
86
|
+
autoload :TooManyMultipartFiles
|
87
|
+
autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
|
88
|
+
autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
|
79
89
|
end
|
80
90
|
end
|
81
91
|
|
@@ -215,6 +225,58 @@ module Grape
|
|
215
225
|
autoload :StreamResponse
|
216
226
|
end
|
217
227
|
end
|
228
|
+
|
229
|
+
module Validations
|
230
|
+
extend ::ActiveSupport::Autoload
|
231
|
+
|
232
|
+
eager_autoload do
|
233
|
+
autoload :AttributesIterator
|
234
|
+
autoload :MultipleAttributesIterator
|
235
|
+
autoload :SingleAttributeIterator
|
236
|
+
autoload :Types
|
237
|
+
autoload :ParamsScope
|
238
|
+
autoload :ValidatorFactory
|
239
|
+
autoload :Base, 'grape/validations/validators/base'
|
240
|
+
end
|
241
|
+
|
242
|
+
module Types
|
243
|
+
extend ::ActiveSupport::Autoload
|
244
|
+
|
245
|
+
eager_autoload do
|
246
|
+
autoload :InvalidValue
|
247
|
+
autoload :DryTypeCoercer
|
248
|
+
autoload :ArrayCoercer
|
249
|
+
autoload :SetCoercer
|
250
|
+
autoload :PrimitiveCoercer
|
251
|
+
autoload :CustomTypeCoercer
|
252
|
+
autoload :CustomTypeCollectionCoercer
|
253
|
+
autoload :MultipleTypeCoercer
|
254
|
+
autoload :VariantCollectionCoercer
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
module Validators
|
259
|
+
extend ::ActiveSupport::Autoload
|
260
|
+
|
261
|
+
eager_autoload do
|
262
|
+
autoload :Base
|
263
|
+
autoload :MultipleParamsBase
|
264
|
+
autoload :AllOrNoneOfValidator
|
265
|
+
autoload :AllowBlankValidator
|
266
|
+
autoload :AsValidator
|
267
|
+
autoload :AtLeastOneOfValidator
|
268
|
+
autoload :CoerceValidator
|
269
|
+
autoload :DefaultValidator
|
270
|
+
autoload :ExactlyOneOfValidator
|
271
|
+
autoload :ExceptValuesValidator
|
272
|
+
autoload :MutualExclusionValidator
|
273
|
+
autoload :PresenceValidator
|
274
|
+
autoload :RegexpValidator
|
275
|
+
autoload :SameAsValidator
|
276
|
+
autoload :ValuesValidator
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
218
280
|
end
|
219
281
|
|
220
282
|
require 'grape/config'
|
@@ -224,25 +286,4 @@ require 'grape/util/lazy_value'
|
|
224
286
|
require 'grape/util/lazy_block'
|
225
287
|
require 'grape/util/endpoint_configuration'
|
226
288
|
|
227
|
-
require 'grape/validations/validators/base'
|
228
|
-
require 'grape/validations/attributes_iterator'
|
229
|
-
require 'grape/validations/single_attribute_iterator'
|
230
|
-
require 'grape/validations/multiple_attributes_iterator'
|
231
|
-
require 'grape/validations/validators/allow_blank'
|
232
|
-
require 'grape/validations/validators/as'
|
233
|
-
require 'grape/validations/validators/at_least_one_of'
|
234
|
-
require 'grape/validations/validators/coerce'
|
235
|
-
require 'grape/validations/validators/default'
|
236
|
-
require 'grape/validations/validators/exactly_one_of'
|
237
|
-
require 'grape/validations/validators/mutual_exclusion'
|
238
|
-
require 'grape/validations/validators/presence'
|
239
|
-
require 'grape/validations/validators/regexp'
|
240
|
-
require 'grape/validations/validators/same_as'
|
241
|
-
require 'grape/validations/validators/values'
|
242
|
-
require 'grape/validations/validators/except_values'
|
243
|
-
require 'grape/validations/params_scope'
|
244
|
-
require 'grape/validations/validators/all_or_none'
|
245
|
-
require 'grape/validations/types'
|
246
|
-
require 'grape/validations/validator_factory'
|
247
|
-
|
248
289
|
require 'grape/version'
|
@@ -1,20 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
describe Grape::Validations do
|
6
|
-
context '
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
context 'deprecated Grape::Validations::Base' do
|
5
|
+
subject do
|
6
|
+
Class.new(Grape::API) do
|
7
|
+
params do
|
8
|
+
requires :text, validator_with_old_base: true
|
9
|
+
end
|
10
|
+
get do
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:validator_with_old_base) do
|
16
|
+
Class.new(Grape::Validations::Base) do
|
17
|
+
def validate_param!(_attr_name, _params)
|
18
|
+
true
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
described_class.register_validator('validator_with_old_base', validator_with_old_base)
|
25
|
+
allow(Warning).to receive(:warn)
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
described_class.deregister_validator('validator_with_old_base')
|
30
|
+
end
|
31
|
+
|
32
|
+
def app
|
33
|
+
subject
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'puts a deprecation warning' do
|
37
|
+
expect(Warning).to receive(:warn) do |message|
|
38
|
+
expect(message).to include('`Grape::Validations::Base` is deprecated')
|
39
|
+
end
|
40
|
+
|
41
|
+
get '/'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'using a custom length validator' do
|
18
46
|
subject do
|
19
47
|
Class.new(Grape::API) do
|
20
48
|
params do
|
@@ -26,6 +54,25 @@ describe Grape::Validations do
|
|
26
54
|
end
|
27
55
|
end
|
28
56
|
|
57
|
+
let(:default_length_validator) do
|
58
|
+
Class.new(Grape::Validations::Validators::Base) do
|
59
|
+
def validate_param!(attr_name, params)
|
60
|
+
@option = params[:max].to_i if params.key?(:max)
|
61
|
+
return if params[attr_name].length <= @option
|
62
|
+
|
63
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
before do
|
69
|
+
described_class.register_validator('default_length', default_length_validator)
|
70
|
+
end
|
71
|
+
|
72
|
+
after do
|
73
|
+
described_class.deregister_validator('default_length')
|
74
|
+
end
|
75
|
+
|
29
76
|
def app
|
30
77
|
subject
|
31
78
|
end
|
@@ -35,11 +82,13 @@ describe Grape::Validations do
|
|
35
82
|
expect(last_response.status).to eq 200
|
36
83
|
expect(last_response.body).to eq 'bacon'
|
37
84
|
end
|
85
|
+
|
38
86
|
it 'over 140 characters' do
|
39
87
|
get '/', text: 'a' * 141
|
40
88
|
expect(last_response.status).to eq 400
|
41
89
|
expect(last_response.body).to eq 'text must be at the most 140 characters long'
|
42
90
|
end
|
91
|
+
|
43
92
|
it 'specified in the query string' do
|
44
93
|
get '/', text: 'a' * 141, max: 141
|
45
94
|
expect(last_response.status).to eq 200
|
@@ -48,15 +97,6 @@ describe Grape::Validations do
|
|
48
97
|
end
|
49
98
|
|
50
99
|
context 'using a custom body-only validator' do
|
51
|
-
before do
|
52
|
-
module CustomValidationsSpec
|
53
|
-
class InBody < Grape::Validations::PresenceValidator
|
54
|
-
def validate(request)
|
55
|
-
validate!(request.env['api.request.body'])
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
100
|
subject do
|
61
101
|
Class.new(Grape::API) do
|
62
102
|
params do
|
@@ -68,6 +108,22 @@ describe Grape::Validations do
|
|
68
108
|
end
|
69
109
|
end
|
70
110
|
|
111
|
+
let(:in_body_validator) do
|
112
|
+
Class.new(Grape::Validations::Validators::PresenceValidator) do
|
113
|
+
def validate(request)
|
114
|
+
validate!(request.env['api.request.body'])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
before do
|
120
|
+
described_class.register_validator('in_body', in_body_validator)
|
121
|
+
end
|
122
|
+
|
123
|
+
after do
|
124
|
+
described_class.deregister_validator('in_body')
|
125
|
+
end
|
126
|
+
|
71
127
|
def app
|
72
128
|
subject
|
73
129
|
end
|
@@ -77,6 +133,7 @@ describe Grape::Validations do
|
|
77
133
|
expect(last_response.status).to eq 200
|
78
134
|
expect(last_response.body).to eq 'bacon'
|
79
135
|
end
|
136
|
+
|
80
137
|
it 'ignores field in query' do
|
81
138
|
get '/', nil, text: 'abc'
|
82
139
|
expect(last_response.status).to eq 400
|
@@ -85,15 +142,6 @@ describe Grape::Validations do
|
|
85
142
|
end
|
86
143
|
|
87
144
|
context 'using a custom validator with message_key' do
|
88
|
-
before do
|
89
|
-
module CustomValidationsSpec
|
90
|
-
class WithMessageKey < Grape::Validations::PresenceValidator
|
91
|
-
def validate_param!(attr_name, _params)
|
92
|
-
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
145
|
subject do
|
98
146
|
Class.new(Grape::API) do
|
99
147
|
params do
|
@@ -105,6 +153,22 @@ describe Grape::Validations do
|
|
105
153
|
end
|
106
154
|
end
|
107
155
|
|
156
|
+
let(:message_key_validator) do
|
157
|
+
Class.new(Grape::Validations::Validators::PresenceValidator) do
|
158
|
+
def validate_param!(attr_name, _params)
|
159
|
+
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
before do
|
165
|
+
described_class.register_validator('with_message_key', message_key_validator)
|
166
|
+
end
|
167
|
+
|
168
|
+
after do
|
169
|
+
described_class.deregister_validator('with_message_key')
|
170
|
+
end
|
171
|
+
|
108
172
|
def app
|
109
173
|
subject
|
110
174
|
end
|
@@ -117,22 +181,6 @@ describe Grape::Validations do
|
|
117
181
|
end
|
118
182
|
|
119
183
|
context 'using a custom request/param validator' do
|
120
|
-
before do
|
121
|
-
module CustomValidationsSpec
|
122
|
-
class Admin < Grape::Validations::Base
|
123
|
-
def validate(request)
|
124
|
-
# return if the param we are checking was not in request
|
125
|
-
# @attrs is a list containing the attribute we are currently validating
|
126
|
-
return unless request.params.key? @attrs.first
|
127
|
-
# check if admin flag is set to true
|
128
|
-
return unless @option
|
129
|
-
# check if user is admin or not
|
130
|
-
# as an example get a token from request and check if it's admin or not
|
131
|
-
raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
184
|
subject do
|
137
185
|
Class.new(Grape::API) do
|
138
186
|
params do
|
@@ -146,6 +194,29 @@ describe Grape::Validations do
|
|
146
194
|
end
|
147
195
|
end
|
148
196
|
|
197
|
+
let(:admin_validator) do
|
198
|
+
Class.new(Grape::Validations::Validators::Base) do
|
199
|
+
def validate(request)
|
200
|
+
# return if the param we are checking was not in request
|
201
|
+
# @attrs is a list containing the attribute we are currently validating
|
202
|
+
return unless request.params.key? @attrs.first
|
203
|
+
# check if admin flag is set to true
|
204
|
+
return unless @option
|
205
|
+
# check if user is admin or not
|
206
|
+
# as an example get a token from request and check if it's admin or not
|
207
|
+
raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
before do
|
213
|
+
described_class.register_validator('admin', admin_validator)
|
214
|
+
end
|
215
|
+
|
216
|
+
after do
|
217
|
+
described_class.deregister_validator('admin')
|
218
|
+
end
|
219
|
+
|
149
220
|
def app
|
150
221
|
subject
|
151
222
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
3
|
module DeeplyIncludedOptionsSpec
|
6
4
|
module Defaults
|
7
5
|
extend ActiveSupport::Concern
|
@@ -41,18 +39,18 @@ describe Grape::API do
|
|
41
39
|
|
42
40
|
it 'works for unspecified format' do
|
43
41
|
get '/users'
|
44
|
-
expect(last_response.status).to
|
42
|
+
expect(last_response.status).to be 200
|
45
43
|
expect(last_response.content_type).to eql 'application/json'
|
46
44
|
end
|
47
45
|
|
48
46
|
it 'works for specified format' do
|
49
47
|
get '/users.json'
|
50
|
-
expect(last_response.status).to
|
48
|
+
expect(last_response.status).to be 200
|
51
49
|
expect(last_response.content_type).to eql 'application/json'
|
52
50
|
end
|
53
51
|
|
54
52
|
it "doesn't work for format different than specified" do
|
55
53
|
get '/users.txt'
|
56
|
-
expect(last_response.status).to
|
54
|
+
expect(last_response.status).to be 404
|
57
55
|
end
|
58
56
|
end
|