class Validator::Validator

Public Class Methods

new(opts={}) click to toggle source

@param [Hash] opts the options to validate a body @option opts [Boolean] :default_values Set default values if the schema

specifies it (if true)

@option opts [Boolean] :delete_extra_properties If the body contains properties

not specified in the schema delete them from the body (if true)
or raise an exception (if false)

@option opts [Boolean] :allow_extra_properties Allow properties

not specified in the schema
# File lib/opennebula/flow/validator.rb, line 72
def initialize(opts={})
    @opts = {
        :default_values => true,
        :delete_extra_properties => false,
        :allow_extra_properties => false
    }.merge(opts)
end

Public Instance Methods

validate!(body, schema, key="") click to toggle source

Recursively validate and modify a JSON body based on a schema.

@see tools.ietf.org/html/draft-zyp-json-schema-03

@param [Hash, Array, String, nil] body JSON represented as Ruby objects @param [Hash] schema that will be used to validate @param [String] key of the body that will be validated in this step

@return [Hash, Array, String, nil] The modified body

@raise [SchemaException] If the schema is not correctly defined @raise [ParseException] if the body does not meet the schema definition

@example Validate a User

schema = {
    :type => :object,
    :properties => {
        'username' => {
            :type => :string
        }
    }
}

hash = {
    'username' => 'pepe'
}

Validator.validate!(hash, schema)
#=> {'username' => 'pepe'}

@note The parameter body will be modified @note Schema options supported

:extends
:type => [:object, :array, :string, :null]
# File lib/opennebula/flow/validator.rb, line 115
def validate!(body, schema, key="")
    if schema[:extends]
        base_schema = schema.delete(:extends)
        schema      = base_schema.deep_merge(schema)
    end

    case schema[:type]
    when :object  then validate_object(body, schema, key)
    when :array   then validate_array(body, schema, key)
    when :string  then validate_string(body, schema, key)
    when :integer then validate_integer(body, schema, key)
    when :null    then validate_null(body, schema, key)
    when :boolean then validate_boolean(body, schema, key)
    else raise SchemaException, "type #{schema[:type]} is not a valid type"
    end
end

Private Instance Methods

check_enum(body_value, schema_string, schema_key) click to toggle source

Validate an string enum

@param [String] body_value to be validated @param [Hash] schema_string of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [String] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :string,
    :enum => ['juan', 'luis']
}

body = "juan"

Validator.check_enum(body, schema)
#=> "juan"

@note The parameter body will be modified @note Schema options supported

:enum
# File lib/opennebula/flow/validator.rb, line 456
def check_enum(body_value, schema_string, schema_key)
    if schema_string[:enum].include?(body_value)
        body_value
    else
        raise ParseException, "KEY: '#{schema_key}' must be one of"\
            " #{schema_string[:enum].join(', ')};"
    end
end
check_format(body_value, schema_string, schema_key) click to toggle source

Validate an string format

@param [String] body_value to be validated @param [Hash] schema_string of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [String] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :string,
    :format => :url
}

body = "http://localhost:4567"

Validator.check_format(body, schema)
#=> "http://localhost:4567"

@note The parameter body will be modified @note Schema options supported

:url
# File lib/opennebula/flow/validator.rb, line 415
def check_format(body_value, schema_string, schema_key)
    case schema_string[:format]
    when :uri
        begin
            require 'uri'
            uri = URI.parse(body_value)
        rescue
            raise ParseException, "KEY: '#{schema_key}' must be a valid URL;"
        end

        body_value
    end

    body_value
end
check_regex(body_value, schema_string, schema_key) click to toggle source

Validate an string regex

@param [String] body_value to be validated @param [Hash] schema_string of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [String] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :string,
    :regex =>  /^\w+$/
}

body = "juan"

Validator.check_regex(body, schema)
#=> "juan"

@note The parameter body will be modified @note Schema options supported

:enum
# File lib/opennebula/flow/validator.rb, line 490
def check_regex(body_value, schema_string, schema_key)
    if schema_string[:regex] =~ body_value
        body_value
    else
        raise ParseException, "KEY: '#{schema_key}' must match regexp #{schema_string[:regex].inspect};"
    end
end
validate_array(body, schema_array, schema_key) click to toggle source

Validate an array type

@param [Array] body to be validated @param [Hash] schema_array of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [Hash] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :array,
    :items => {
        :type => :string
    }
}

body = ['pepe', 'luis', 'juan']

Validator.validate_array(body, schema)
#=> 'username' => ['pepe', 'luis', 'juan']

@note The parameter body will be modified @note Schema options supported

:items
# File lib/opennebula/flow/validator.rb, line 235
def validate_array(body, schema_array, schema_key)
    if body.instance_of?(Array)
        body.collect { |body_item|
            validate!(body_item, schema_array[:items], schema_key)
        }
    else
        raise ParseException, "KEY: '#{schema_key}' must be an Array;"
    end
end
validate_boolean(body, schema_boolean, schema_key) click to toggle source

Validate an boolean type

@param [Object] body to be validated @param [Hash] schema_boolean of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [nil]

@raise [ParseException] if the body is not a boolean

@example Validate array

schema = {
    :type => :boolean
}

body = true

Validator.validate_boolean(body, schema)
#=> nil
# File lib/opennebula/flow/validator.rb, line 340
def validate_boolean(body, schema_boolean, schema_key)
    if body != true && body != false
        raise ParseException, "KEY: '#{schema_key}' is not allowed;"
    end

    body
end
validate_integer(body, schema_array, schema_key) click to toggle source

Validate an integer type

@param [Array] body to be validated @param [Hash] schema_array of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [Hash] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :integer
}

body = 5

Validator.validate_integer(body, schema)
#=> 5
# File lib/opennebula/flow/validator.rb, line 266
def validate_integer(body, schema_array, schema_key)
    value = Integer(body)

    if schema_array[:maximum]
        excl = schema_array[:exclusiveMaximum]
        max = schema_array[:maximum]
        if !(excl ? value < max : value <= max)
            raise ParseException, "KEY: '#{schema_key}' must be "\
                "lower than #{excl ? '' : 'or equal to'} #{max};"
        end
    end

    if schema_array[:minimum]
        excl = schema_array[:exclusiveMinimum]
        min = schema_array[:minimum]
        if !(excl ? value > min : value >= min)
            raise ParseException, "KEY: '#{schema_key}' must be "\
                "greater than #{excl ? '' : 'or equal to'} #{min};"
        end
    end

    value
rescue ArgumentError
    raise ParseException, "KEY: '#{schema_key}' must be an Integer;"
end
validate_null(body, schema_null, schema_key) click to toggle source

Validate an null type

@param [nil] body to be validated @param [Hash] schema_null of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [nil]

@raise [ParseException] if the body is not nil

@example Validate array

schema = {
    :type => :null
}

body = nil

Validator.validate_null(body, schema)
#=> nil
# File lib/opennebula/flow/validator.rb, line 313
def validate_null(body, schema_null, schema_key)
    if body != nil
        raise ParseException, "KEY: '#{schema_key}' is not allowed;"
    end
end
validate_object(body, schema_object, key) click to toggle source

Validate an object type

@param [Hash] body to be validated @param [Hash] schema_object of the objectto validate the body @param [String] key of the body that will be validated in this step

@return [Hash] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate with default values

schema_body = {
    :type => :object,
    :properties => {
        'username' => {
            :type => :string,
            :default => 'def'
        }
    }

body = {}

Validator.validate_object(body, schema_body)
#=> {'username' => 'def'}

@note The parameter body will be modified @note Schema options supported

:properties
:required
:default
# File lib/opennebula/flow/validator.rb, line 165
def validate_object(body, schema_object, key)
    unless body.is_a?(Hash)
        raise ParseException, "KEY: #{key} must be a Hash; SCHEMA:"
    end

    new_body = body.dup

    schema_object[:properties].each{ |schema_key, schema_value|
        body_value = new_body.delete(schema_key)

        if body_value
            body[schema_key] = validate!(body_value, schema_value,
                                    schema_key)
        else
            if schema_value[:required]
                raise ParseException, "KEY: '#{schema_key}' is required;"
            end

            if @opts[:default_values] && schema_value[:default]
                body[schema_key] = schema_value[:default]
            end
        end
    }

    # raise error if body.keys is not empty
    unless new_body.keys.empty?
        if @opts[:delete_extra_properties]
            new_body.keys.each{ |key|
                body.delete(key)
            }
        else
            if @opts[:allow_extra_properties]
                return body
            else
                raise ParseException, "KEY: #{new_body.keys.join(', ')} not"\
                    " allowed;"
            end
        end
    end

    body
end
validate_string(body, schema_string, schema_key) click to toggle source

Validate an string type

@param [String] body to be validated @param [Hash] schema_string of the object to validate the body @param [String] schema_key of the body that will be validated in this step

@return [String] The modified body

@raise [ParseException] if the body does not meet the schema definition

@example Validate array

schema = {
    :type => :string
}

body = "pepe"

Validator.validate_string(body, schema)
#=> "pepe"

@note The parameter body will be modified @note Schema options supported

:format
:enum
:regex
# File lib/opennebula/flow/validator.rb, line 374
def validate_string(body, schema_string, schema_key)
    if body.instance_of?(String)
        if schema_string[:format]
            check_format(body, schema_string, schema_key)
        elsif schema_string[:enum]
            check_enum(body, schema_string, schema_key)
        elsif schema_string[:regex]
            check_regex(body, schema_string, schema_key)
        else
            body
        end
    else
        raise ParseException, "KEY: '#{schema_key}' must be a String;"
    end
end