request_params_validation 0.1.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 (31) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +557 -0
  4. data/Rakefile +32 -0
  5. data/lib/request_params_validation.rb +346 -0
  6. data/lib/request_params_validation/definitions.rb +57 -0
  7. data/lib/request_params_validation/definitions/action.rb +23 -0
  8. data/lib/request_params_validation/definitions/param.rb +182 -0
  9. data/lib/request_params_validation/definitions/request.rb +31 -0
  10. data/lib/request_params_validation/definitions/resource.rb +30 -0
  11. data/lib/request_params_validation/engine.rb +18 -0
  12. data/lib/request_params_validation/exceptions/base_errors.rb +10 -0
  13. data/lib/request_params_validation/exceptions/definitions_errors.rb +31 -0
  14. data/lib/request_params_validation/exceptions/validator_errors.rb +49 -0
  15. data/lib/request_params_validation/handler.rb +26 -0
  16. data/lib/request_params_validation/helpers.rb +17 -0
  17. data/lib/request_params_validation/params.rb +60 -0
  18. data/lib/request_params_validation/params/constants.rb +22 -0
  19. data/lib/request_params_validation/params/converter.rb +33 -0
  20. data/lib/request_params_validation/params/types/conversions.rb +41 -0
  21. data/lib/request_params_validation/params/types/validations.rb +57 -0
  22. data/lib/request_params_validation/params/validator.rb +74 -0
  23. data/lib/request_params_validation/params/validators/custom.rb +18 -0
  24. data/lib/request_params_validation/params/validators/format.rb +27 -0
  25. data/lib/request_params_validation/params/validators/inclusion.rb +27 -0
  26. data/lib/request_params_validation/params/validators/length.rb +37 -0
  27. data/lib/request_params_validation/params/validators/presence.rb +13 -0
  28. data/lib/request_params_validation/params/validators/type.rb +59 -0
  29. data/lib/request_params_validation/params/validators/value.rb +37 -0
  30. data/lib/request_params_validation/version.rb +3 -0
  31. metadata +87 -0
@@ -0,0 +1,22 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Constants
4
+ HASH_TYPE = :hash
5
+ ARRAY_TYPE = :array
6
+ STRING_TYPE = :string
7
+ INTEGER_TYPE = :integer
8
+ DECIMAL_TYPE = :decimal
9
+ BOOLEAN_TYPE = :boolean
10
+ DATE_TYPE = :date
11
+ DATETIME_TYPE = :datetime
12
+ EMAIL_TYPE = :email
13
+
14
+ INTEGER_REGEXP = /^[+-]?([1-9]\d*|0)$/
15
+ DECIMAL_REGEXP = /^[+-]?([1-9]\d*|0)(\.[0-9]+)?$/
16
+ EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
17
+
18
+ BOOLEAN_TRUE_VALUES = [true, 'true'] + RequestParamsValidation.extends.boolean_true_values
19
+ BOOLEAN_FALSE_VALUES = [false, 'false'] + RequestParamsValidation.extends.boolean_false_values
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ require 'request_params_validation/params/types/conversions'
2
+
3
+ module RequestParamsValidation
4
+ module Params
5
+ module Converter
6
+ extend Params::Types::Conversions
7
+
8
+ def self.coerce(param, value)
9
+ type = param.type
10
+
11
+ method_name = "convert_to_#{type}"
12
+
13
+ return value unless self.respond_to?(method_name)
14
+
15
+ if [Params::DATE_TYPE, Params::DATETIME_TYPE].include?(type)
16
+ self.send(method_name, value, param.format.try(:strptime))
17
+ elsif type == Params::DECIMAL_TYPE
18
+ self.send(method_name, value, param.decimal_precision)
19
+ else
20
+ self.send(method_name, value)
21
+ end
22
+ end
23
+
24
+ def self.apply_transformation(param, value)
25
+ transform = param.transform
26
+
27
+ return value unless transform
28
+
29
+ transform.respond_to?(:call) ? transform.call(value) : value.send(transform)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,41 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Types
4
+ module Conversions
5
+ def convert_to_string(value)
6
+ String(value)
7
+ end
8
+
9
+ def convert_to_integer(value)
10
+ Integer(value)
11
+ end
12
+
13
+ def convert_to_decimal(value, precision)
14
+ precision = precision || RequestParamsValidation.formats.decimal_precision
15
+
16
+ value = Float(value)
17
+
18
+ value = value.round(precision) if precision
19
+
20
+ value
21
+ end
22
+
23
+ def convert_to_boolean(value)
24
+ Params::BOOLEAN_TRUE_VALUES.include?(value)
25
+ end
26
+
27
+ def convert_to_date(value, format)
28
+ format = format || RequestParamsValidation.formats.date
29
+
30
+ format ? Date.strptime(value, format) : Date.parse(value)
31
+ end
32
+
33
+ def convert_to_datetime(value, format)
34
+ format = format || RequestParamsValidation.formats.datetime
35
+
36
+ format ? DateTime.strptime(value, format) : DateTime.parse(value)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Types
4
+ module Validations
5
+ def valid_array?(value)
6
+ value.is_a?(Array)
7
+ end
8
+
9
+ def valid_hash?(value)
10
+ value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
11
+ rescue NameError # For older versions of Rails
12
+ false
13
+ end
14
+
15
+ def valid_string?(value)
16
+ true
17
+ end
18
+
19
+ def valid_integer?(value)
20
+ !!(value.to_s =~ Params::INTEGER_REGEXP)
21
+ end
22
+
23
+ def valid_decimal?(value)
24
+ !!(value.to_s =~ Params::DECIMAL_REGEXP)
25
+ end
26
+
27
+ def valid_email?(value)
28
+ !!(value =~ Params::EMAIL_REGEXP)
29
+ end
30
+
31
+ def valid_boolean?(value)
32
+ (Params::BOOLEAN_TRUE_VALUES + Params::BOOLEAN_FALSE_VALUES).include?(value)
33
+ end
34
+
35
+ def valid_date?(value, format)
36
+ format = format || RequestParamsValidation.formats.date
37
+
38
+ format ? Date.strptime(value, format) : Date.parse(value)
39
+
40
+ true
41
+ rescue ArgumentError, TypeError
42
+ false
43
+ end
44
+
45
+ def valid_datetime?(value, format)
46
+ format = format || RequestParamsValidation.formats.datetime
47
+
48
+ format ? DateTime.strptime(value, format) : DateTime.parse(value)
49
+
50
+ true
51
+ rescue ArgumentError, TypeError
52
+ false
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,74 @@
1
+ require 'request_params_validation/params/converter'
2
+
3
+ Dir[File.join(File.dirname(__FILE__), 'validators/**/*.rb')].each { |f| require f }
4
+
5
+ module RequestParamsValidation
6
+ module Params
7
+ class Validator
8
+
9
+ Validators.constants(false).each do |validator|
10
+ include Validators.const_get(validator)
11
+ end
12
+
13
+ attr_reader :param, :value, :original_value
14
+
15
+ def initialize(param_definition, value)
16
+ @param = param_definition
17
+ @value = value
18
+ @original_value = value
19
+ end
20
+
21
+ def validate_and_coerce
22
+ validate_presence! if param.validate_presence?
23
+
24
+ if value.blank? && param.has_default?
25
+ @value = param.default
26
+ return value
27
+ end
28
+
29
+ return value if value.nil?
30
+
31
+ validate_type! if param.validate_type?
32
+
33
+ case param.type
34
+ when Params::ARRAY_TYPE
35
+ iterate_array
36
+ when Params::HASH_TYPE
37
+ iterate_hash
38
+ end
39
+
40
+ @value = Params::Converter.coerce(param, value)
41
+
42
+ validate_inclusion! if param.validate_inclusion?
43
+ validate_length! if param.validate_length?
44
+ validate_value! if param.validate_value?
45
+ validate_format! if param.validate_format?
46
+ validate_custom_validation! if param.validate_custom_validation?
47
+
48
+ @value = Params::Converter.apply_transformation(param, value)
49
+ end
50
+
51
+ private
52
+
53
+ def iterate_array
54
+ value.map! do |element_value|
55
+ self.class.new(param.elements, element_value).validate_and_coerce
56
+ end
57
+ end
58
+
59
+ def iterate_hash
60
+ Params::validate!(param.sub_definition, value) # recursion for the sub_definition
61
+ end
62
+
63
+ def raise_error(exception_type, options = {})
64
+ options = options.merge(
65
+ param_key: param.key,
66
+ param_value: original_value,
67
+ param_type: param.type
68
+ )
69
+
70
+ raise RequestParamsValidation.exceptions.send(exception_type).new(options)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,18 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Custom
5
+ def validate_custom_validation!
6
+ result = param.custom_validation.function.call(value)
7
+
8
+ unless result
9
+ raise_error(
10
+ :on_invalid_parameter_custom_validation,
11
+ details: param.custom_validation.message
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Format
5
+ def validate_format!
6
+ regexp = param.format.regexp
7
+
8
+ if value !~ regexp
9
+ raise_error(
10
+ :on_invalid_parameter_format,
11
+ regexp: regexp,
12
+ details: param.format.message || default_invalid_format_message
13
+ )
14
+ end
15
+ end
16
+
17
+ def default_invalid_format_message
18
+ if param.element_of_array?
19
+ 'An element of the array has an invalid format'
20
+ else
21
+ 'Value format is invalid'
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Inclusion
5
+ def validate_inclusion!
6
+ include_in = param.inclusion.in
7
+
8
+ unless include_in.include?(value)
9
+ raise_error(
10
+ :on_invalid_parameter_inclusion,
11
+ include_in: include_in,
12
+ details: param.inclusion.message || default_invalid_inclusion_message(include_in)
13
+ )
14
+ end
15
+ end
16
+
17
+ def default_invalid_inclusion_message(include_in)
18
+ if param.element_of_array?
19
+ "All elements values of the array should be in #{include_in}"
20
+ else
21
+ "Value should be in #{include_in}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Length
5
+ def validate_length!
6
+ min = param.length.min
7
+ max = param.length.max
8
+
9
+ if (min && value.length < min) || (max && value.length > max)
10
+ raise_error(
11
+ :on_invalid_parameter_length,
12
+ min: min,
13
+ max: max,
14
+ details: param.length.message || default_invalid_length_message(min, max)
15
+ )
16
+ end
17
+ end
18
+
19
+ def default_invalid_length_message(min, max)
20
+ message = if param.element_of_array?
21
+ 'All elements of the array should have a length'
22
+ else
23
+ 'Length should be'
24
+ end
25
+
26
+ if min && max
27
+ min == max ? "#{message} equal to #{max}" : "#{message} between #{min} and #{max}"
28
+ elsif min
29
+ "#{message} greater or equal than #{min}"
30
+ else
31
+ "#{message} less or equal than #{max}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Presence
5
+ def validate_presence!
6
+ not_present = param.allow_blank ? value.nil? : value.blank?
7
+
8
+ raise_error(:on_missing_parameter) if not_present
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,59 @@
1
+ require 'request_params_validation/params/types/validations'
2
+
3
+ module RequestParamsValidation
4
+ module Params
5
+ module Validators
6
+ module Type
7
+ include Params::Types::Validations
8
+ include RequestParamsValidation.extends.types if RequestParamsValidation.extends.types
9
+
10
+ def validate_type!
11
+ type = param.type
12
+
13
+ method_name = "valid_#{type}?"
14
+
15
+ unless self.respond_to?(method_name)
16
+ raise UnsupportedTypeError.new(param_key: param.key, param_type: type)
17
+ end
18
+
19
+ valid = if [Params::DATE_TYPE, Params::DATETIME_TYPE].include?(type)
20
+ self.send(method_name, value, param.format.try(:strptime))
21
+ else
22
+ self.send(method_name, value)
23
+ end
24
+
25
+ unless valid
26
+ raise_error(
27
+ :on_invalid_parameter_type,
28
+ details: default_invalid_type_message(type)
29
+ )
30
+ end
31
+ end
32
+
33
+ def default_invalid_type_message(type)
34
+ type = :object if type == Params::HASH_TYPE
35
+
36
+ message = if param.element_of_array?
37
+ "All elements of the array should be a valid #{type}"
38
+ else
39
+ "Value should be a valid #{type}"
40
+ end
41
+
42
+ if [Params::DATE_TYPE, Params::DATETIME_TYPE].include?(type)
43
+ format = param.format.try(:strptime) || RequestParamsValidation.formats.send(type)
44
+
45
+ if format
46
+ message = if param.format.try(:message)
47
+ param.format.message
48
+ else
49
+ "#{message} with the format #{format}"
50
+ end
51
+ end
52
+ end
53
+
54
+ message
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,37 @@
1
+ module RequestParamsValidation
2
+ module Params
3
+ module Validators
4
+ module Value
5
+ def validate_value!
6
+ min = param.value.min
7
+ max = param.value.max
8
+
9
+ if (min && value < min) || (max && value > max)
10
+ raise_error(
11
+ :on_invalid_parameter_value_size,
12
+ min: min,
13
+ max: max,
14
+ details: param.value.message || default_invalid_value_message(min, max)
15
+ )
16
+ end
17
+ end
18
+
19
+ def default_invalid_value_message(min, max)
20
+ message = if param.element_of_array?
21
+ 'All elements of the array should have a value'
22
+ else
23
+ 'Value should be'
24
+ end
25
+
26
+ if min && max
27
+ "#{message} between #{min} and #{max}"
28
+ elsif min
29
+ "#{message} greater or equal than #{min}"
30
+ else
31
+ "#{message} less or equal than #{max}"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end