Module: ApiEngineBase::ArgumentValidation::InstanceMethods

Defined in:
app/services/api_engine_base/argument_validation/instance_methods.rb

Instance Method Summary collapse

Instance Method Details

#__failed_argument_validation(msg:, argument:, metadata:, error: ApiEngineBase::ServiceBase::ArgumentValidationError) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 121

def __failed_argument_validation(msg:, argument:, metadata:, error: ApiEngineBase::ServiceBase::ArgumentValidationError)
  case self.class.on_argument_validation_assigned
  when :raise
    raise error, msg
  when :fail_early
    @context_validation_failures ||= {}
    @context_validation_failures[argument] = {
      msg: msg,
      required: [:requirement],
      is_a: [:is_a],
    }
    # When gracefully failing, it will find all failures first before setting appropriate
    # context variables -- Check out continue_with_logical_code!
  else
    context.invalid_arguments = true
    log_warn(msg)
  end
end

#continue_with_logical_code!Object



13
14
15
16
17
18
19
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 13

def continue_with_logical_code!
  return if @context_validation_failures.nil?

  invalid_argument_keys = @context_validation_failures.keys
  msg = @context_validation_failures.map { |_k, obj| obj[:msg] }.join(", ")
  context.fail!(msg:, invalid_argument_hash: @context_validation_failures, invalid_argument_keys:, invalid_arguments: true)
end

#inline_argument_failure!(errors:) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 21

def inline_argument_failure!(errors:)
  errors = errors.to_hash
  invalid_argument_keys = errors.keys
  invalid_argument_hash = {}
  human_readable = []

  errors.each do |k, v|
    error_message = Array(v).join(", ")
    invalid_argument_hash[k] = { msg: error_message }
    human_readable << "#{k}: #{error_message}"
  end

  msg = "Invalid arguments: #{human_readable.join(", ")}"
  context.fail!(msg:, invalid_argument_hash:, invalid_argument_keys:, invalid_arguments: true)
end

#run_validations!Object



5
6
7
8
9
10
11
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 5

def run_validations!
  context.valid_arguments = true

  validate_param!
  validate_compositions!
  continue_with_logical_code!
end

#sanitize_paramsObject



140
141
142
143
144
145
146
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 140

def sanitize_params
  self.class.sensitive_params.each do |param|
    next if context.send(param).nil?

    context.send("#{param}=","[FILTERED]")
  end
end

#validate_compositions!Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 84

def validate_compositions!
  self.class.compositions.each do |type, |
    value_list = {}

    [:keys].each do |argument|
      value = context.public_send(argument)
      next if value.nil?

      value_list[argument] = value
    end

    composition_result = [:validation_proc].(value_list.count, value_list.keys)

    next if value_list.count == 0 && ![:required]

    if !composition_result[:is_valid]
      composition_result[:message]
      context.client_composite_error = composition_result[:requirement]
      msg = "Composite Key failure for #{type} [#{[:name]}]. #{composition_result[:message]}. Provided values for the following keys: #{value_list.keys}. Available keys #{[:keys]}"
      __failed_argument_validation(msg:, argument: [:name], metadata: ,error: ApiEngineBase::ServiceBase::CompositionValidationError)
      next
    end

    if [:delegation]
      context.public_send("#{[:name]}=", value_list.first[1])
      context.public_send("#{[:name]}_key=", value_list.first[0])
    end
  end
end

#validate_param!Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 37

def validate_param!
  self.class.validate_params.each do ||
    value = context.public_send([:name])
    use_length = [:length]
    if [:required] && value.nil?
      __failed_argument_validation(msg: "Parameter [#{[:name]}] is required but not present", argument: [:name], metadata:)
    end

    if value.nil? && [:default]
      context.public_send(:"#{[:name]}=", [:default])
      next
    elsif value.nil?
      next
    end

    if is_a = [:is_a]
      direct_type = false
      ancestor_type = false

      # Check if direct type of `is_a` Integer === 5 => true
      direct_type = Array(is_a).none? { _1 === value }

      # If it is a direct type, we dont need to do any other type of checking
      if direct_type == true
        lineage = value.ancestors rescue []
        # Check inclusion in ancestor list
        ancestor_type = Array(is_a).none? { lineage.include?(_1) }
      end
      if direct_type && ancestor_type
        __failed_argument_validation(msg: "Parameter [#{[:name]}] must be of type #{is_a}. Given #{value.class} [#{value}]", argument: [:name], metadata:)
      end
    end

    if [:is_one]
      if Array([:is_one]).none? { _1 == value }
        __failed_argument_validation(msg: "Parameter [#{[:name]}] must be one of #{Array([:is_one])}. Given #{value}", argument: [:name], metadata:)
      end
    end

    validate_sign!(name: [:name], value:, sign: "lt", validation: [:lte], use_length:, metadata:) { (use_length ? value.length : value) <= _1 }
    validate_sign!(name: [:name], value:, sign: "lte", validation: [:lt], use_length:, metadata:) { (use_length ? value.length : value) < _1 }
    validate_sign!(name: [:name], value:, sign: "eq", validation: [:eq], use_length:, metadata:) { (use_length ? value.length : value) == _1 }
    validate_sign!(name: [:name], value:, sign: "gte", validation: [:gte], use_length:, metadata:) { (use_length ? value.length : value) >= _1 }
    validate_sign!(name: [:name], value:, sign: "gt", validation: [:gt], use_length:, metadata:) { (use_length ? value.length : value) > _1 }
  end
end

#validate_sign!(name:, value:, sign:, validation:, use_length:, metadata:) ⇒ Object



114
115
116
117
118
119
# File 'app/services/api_engine_base/argument_validation/instance_methods.rb', line 114

def validate_sign!(name:, value:, sign:, validation:, use_length:, metadata:)
  return if validation.nil?
  return if yield(validation)

  __failed_argument_validation(metadata:, msg: "Parameter [#{name}]#{ " lengths" if use_length} must be #{sign} to #{validation}. Given #{value}", argument: name)
end