Class: Kabk::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/kabk/validator.rb

Overview

Handles input sanitization (strong parameters) and validation

Class Method Summary collapse

Class Method Details

.validate_and_sanitize!(resource, params, is_update: false) ⇒ Hash

Sanitizes input parameters against defined fields and validates them

Parameters:

  • resource (Kabk::Resource)
  • params (Hash)

    Request payload

  • is_update (Boolean) (defaults to: false)

    Is this a PUT/update request?

Returns:

  • (Hash)

    Sanitized parameters ready for Sequel

Raises:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
# File 'lib/kabk/validator.rb', line 13

def self.validate_and_sanitize!(resource, params, is_update: false)
  sanitized = {}
  errors = {}

  # Iterate through all non-readonly fields defined in the schema
  resource.fields.each do |field|
    next if field.primary_key || field.readonly
    # The frontend might not send a field if it wasn't modified, but if required, we must check (unless it's an update and field is absent)

    key_sym = field.name.to_sym
    key_str = field.name.to_s
    has_key = params.key?(key_sym) || params.key?(key_str)
    value = params[key_sym] || params[key_str]

    if field.required && !has_key && !is_update
      errors[key_str] = ["This field is required"]
      next
    end

    if has_key
      if value.nil? || value.to_s.strip.empty?
        if field.required
          errors[key_str] = ["This field is required"]
        elsif !field.nullable && field.type != "boolean"
          # if it's an empty string and not nullable, maybe reject unless it's a string type that allows empty
          # But let's assume empty string might be invalid if min_length is enforced
        end
      end

      # Validate min/max length
      if field.validation
        if field.type == "string" && value.is_a?(String)
          min_len = field.validation[:min_length] || field.validation["min_length"]
          max_len = field.validation[:max_length] || field.validation["max_length"]
          
          if min_len && value.length < min_len
            errors[key_str] = ["Minimum length is #{min_len}"]
          end
          if max_len && value.length > max_len
            errors[key_str] = ["Maximum length is #{max_len}"]
          end
        end
      end

      sanitized[key_sym] = value
    end
  end

  # Note: For OCC, we also need the concurrency_field, even if it's readonly
  if resource.concurrency_field
    c_field = resource.concurrency_field
    if params.key?(c_field.to_sym) || params.key?(c_field.to_s)
      sanitized[c_field.to_sym] = params[c_field.to_sym] || params[c_field.to_s]
    end
  end

  raise ValidationError.new(fields: errors) unless errors.empty?

  sanitized
end