Module: GRApiManager::Validator

Defined in:
lib/gr_api_manager.rb

Overview


Validator — declarative schema and type validation.

Constant Summary collapse

EMAIL_REGEX =
/\A[^\s@]+@[^\s@]+\.[^\s@]+\z/
URL_REGEX =
/\Ahttps?:\/\/\S+\z/i

Class Method Summary collapse

Class Method Details

.validate(params, schema) ⇒ Object

Validates params against schema (Hash of field => expected_type). Returns [is_valid, errors_hash].



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/gr_api_manager.rb', line 124

def self.validate(params, schema)
  errors = {}

  schema.each do |field, rule|
    key = field.to_sym
    val = params[key]

    # Check presence
    if val.nil? || (val.is_a?(String) && val.strip.empty?)
      errors[key] = "is required"
      next
    end

    # Validate type / contract rule
    error_msg = validate_rule(val, rule)
    errors[key] = error_msg if error_msg
  end

  [errors.empty?, errors]
end

.validate_rule(val, rule) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/gr_api_manager.rb', line 147

def self.validate_rule(val, rule)
  case rule
  when :email
    "must be a valid email address" unless val.to_s.match?(EMAIL_REGEX)
  when :url
    "must be a valid URL (http/https)" unless val.to_s.match?(URL_REGEX)
  when :boolean
    "must be a boolean (true or false)" unless val == true || val == false
  when :file
    "must be an uploaded file" unless val.is_a?(GRApiManager::FilePayload)
  when Class
    if rule == Integer
      "must be an Integer" unless val.is_a?(Integer)
    elsif rule == Float
      "must be a Float" unless val.is_a?(Float)
    elsif rule == Numeric
      "must be a Numeric" unless val.is_a?(Numeric)
    elsif rule == String
      "must be a String" unless val.is_a?(String)
    elsif rule == Hash
      "must be an Object/Hash" unless val.is_a?(Hash)
    elsif rule == Array
      "must be an Array" unless val.is_a?(Array)
    else
      "must be a #{rule}" unless val.is_a?(rule)
    end
  when Array
    "must be one of: #{rule.map(&:to_s).join(', ')}" unless rule.map(&:to_s).include?(val.to_s)
  when Regexp
    "does not match expected format" unless val.to_s.match?(rule)
  when Proc
    "is invalid" unless rule.call(val)
  end
end