module Openc::JsonSchema::Validator
Public Instance Methods
validate(schema_path, record)
click to toggle source
# File lib/openc/json_schema/validator.rb, line 6 def validate(schema_path, record) validator = Utils.load_validator(schema_path, record) errors = validator.validate # For now, we just handle the first error. error = errors[0] return if error.nil? convert_error(extract_error(error, record, validator)) end
Private Instance Methods
convert_error(error)
click to toggle source
# File lib/openc/json_schema/validator.rb, line 80 def convert_error(error) path = fragment_to_path(error[:fragment]) extra_params = {} case error[:failed_attribute] when 'Required' match = error[:message].match(/required property of '(.*)'/) missing_property = match[1] path = fragment_to_path("#{error[:fragment]}/#{missing_property}") type = :missing message = "Missing required property: #{path}" when 'AdditionalProperties' match = error[:message].match(/contains additional properties \["(.*)"\] outside of the schema/) additional_property = match[1].split('", "')[0] path = fragment_to_path("#{error[:fragment]}/#{additional_property}") type = :additional message = "Disallowed additional property: #{path}" when 'OneOf' if error[:message].match(/did not match any/) type = :one_of_no_matches message = "No match for property: #{path}" else type = :one_of_many_matches message = "Multiple possible matches for property: #{path}" end when 'AnyOf' type = :any_of_no_matches message = "No match for property: #{path}" when 'MinLength' match = error[:message].match(/minimum string length of (\d+) in/) min_length = match[1].to_i type = :too_short message = "Property too short: #{path} (must be at least #{min_length} characters)" extra_params = {:length => min_length} when 'MaxLength' match = error[:message].match(/maximum string length of (\d+) in/) max_length = match[1].to_i type = :too_long message = "Property too long: #{path} (must be at most #{max_length} characters)" extra_params = {:length => max_length} when 'TypeV4' match = error[:message].match(/the following types?: ([\w\s,]+) in schema/) allowed_types = match[1].split(',').map(&:strip) type = :type_mismatch message = "Property of wrong type: #{path} (must be of type #{allowed_types.join(', ')})" extra_params = {:allowed_types => allowed_types} when 'Enum' match = error[:message].match(/the following values: ([\w\s,]+) in schema/) allowed_values = match[1].split(',').map(&:strip) type = :enum_mismatch if allowed_values.size == 1 message = "Property must have value #{allowed_values[0]}: #{path}" else message = "Property not an allowed value: #{path} (must be one of #{allowed_values.join(', ')})" end extra_params = {:allowed_values => allowed_values} else if error[:message].match(/must be of format yyyy-mm-dd/) type = :format_mismatch message = "Property not of expected format: #{path} (must be of format yyyy-mm-dd)" extra_params = {:expected_format => 'yyyy-mm-dd'} elsif error[:message].match(/must not be blank/) type = :format_mismatch message = "Property not of expected format: #{path} (must not be blank)" else type = :unknown message = "Error of unknown type: #{path} (#{error[:message]})" end end {:type => type, :path => path, :message => message}.merge(extra_params) end
extract_error(error, record, validator)
click to toggle source
# File lib/openc/json_schema/validator.rb, line 35 def extract_error(error, record, validator) if error[:failed_attribute] == 'OneOf' if error[:message].match(/did not match any/) record = JsonPointer.new(record, error[:fragment][1..-1]).value schema = JSON::Validator.schema_for_uri(error[:schema]).schema path = fragment_to_path(error[:fragment]) one_of = walk_schema(schema, path.split('.')).each_with_index # Try to report errors for relevant `oneOf` schemas only. schemas_matching_type = case record when Hash one_of.select{|schema, _| schema.key?('properties')} when String one_of.select{|schema, _| schema['type'] == 'string' || schema['type'].nil? && schema['properties'].nil?} when Integer one_of.select{|schema, _| schema['type'] == 'integer'} when Array one_of.select{|schema, _| schema['type'] == 'array'} else raise "Unexpected type #{record.class.name} for #{record.inspect} at #{path}" end matches = schemas_matching_type.size if matches == 1 i = schemas_matching_type[0][1] return error[:errors][:"oneof_#{i}"][0] end if matches > 1 && record.is_a?(Hash) schemas_matching_type.each do |schema, i| schema['properties'].each do |key, value| if value['enum'] && value['enum'].include?(record[key]) return error[:errors][:"oneof_#{i}"][0] end end end end end end error end
fragment_to_path(fragment)
click to toggle source
# File lib/openc/json_schema/validator.rb, line 161 def fragment_to_path(fragment) fragment.sub(/^#?\/*/, '').gsub('/', '.') end
walk_schema(schema, path)
click to toggle source
Returns the value of the `oneOf` keyword that is within the given schema at the given path.
@param [Hash] schema a schema @param [Array<String>] path a path, based on a JSON Pointer @return [Array<Hash>] the value of the `oneOf` keyword
# File lib/openc/json_schema/validator.rb, line 25 def walk_schema(schema, path) if schema.key?('oneOf') schema['oneOf'] elsif schema.key?('properties') walk_schema(schema['properties'].fetch(path.shift), path) elsif schema.key?('items') walk_schema(schema['items'], path.drop(1)) end end