Skip to content

Commit

Permalink
Merge pull request #669 from dmksnnk/nullable-in-definitions
Browse files Browse the repository at this point in the history
Add support for null values in jsonschema validation
  • Loading branch information
dtkav committed Aug 29, 2018
2 parents cd2b8e4 + d248434 commit 86b5059
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
39 changes: 36 additions & 3 deletions connexion/decorators/validation.py
Expand Up @@ -5,7 +5,8 @@
import sys

import six
from jsonschema import Draft4Validator, ValidationError, draft4_format_checker
from jsonschema import (Draft4Validator, ValidationError,
draft4_format_checker, validators)
from werkzeug import FileStorage

from ..exceptions import ExtraParameterProblem
Expand Down Expand Up @@ -74,6 +75,38 @@ def validate_parameter_list(request_params, spec_params):
return request_params.difference(spec_params)


def extend_with_nullable_support(validator_class):
"""Add support for null values in body.
It adds property validator to given validator_class.
:param validator_class: validator to add nullable support
:type validator_class: jsonschema.IValidator
:return: new validator with added nullable support in properties
:rtype: jsonschema.IValidator
"""
validate_properties = validator_class.VALIDATORS['properties']

def nullable_support(validator, properties, instance, schema):
null_properties = {}
for property_, subschema in six.iteritems(properties):
if isinstance(instance, collections.Iterable) and \
property_ in instance and \
instance[property_] is None and \
subschema.get('x-nullable') is True:
# exclude from following validation
null_properties[property_] = instance.pop(property_)
for error in validate_properties(validator, properties, instance, schema):
yield error
# add null properties back
if null_properties:
instance.update(null_properties)
return validators.extend(validator_class, {'properties': nullable_support})


Draft4ValidatorSupportNullable = extend_with_nullable_support(Draft4Validator)


class RequestBodyValidator(object):
def __init__(self, schema, consumes, api, is_null_value_valid=False, validator=None,
strict_validation=False):
Expand All @@ -90,7 +123,7 @@ def __init__(self, schema, consumes, api, is_null_value_valid=False, validator=N
self.schema = schema
self.has_default = schema.get('default', False)
self.is_null_value_valid = is_null_value_valid
validatorClass = validator or Draft4Validator
validatorClass = validator or Draft4ValidatorSupportNullable
self.validator = validatorClass(schema, format_checker=draft4_format_checker)
self.api = api
self.strict_validation = strict_validation
Expand Down Expand Up @@ -160,7 +193,7 @@ def __init__(self, schema, validator=None):
against API schema. Default is jsonschema.Draft4Validator.
:type validator: jsonschema.IValidator
"""
ValidatorClass = validator or Draft4Validator
ValidatorClass = validator or Draft4ValidatorSupportNullable
self.validator = ValidatorClass(schema, format_checker=draft4_format_checker)

def validate_schema(self, data, url):
Expand Down
35 changes: 34 additions & 1 deletion tests/decorators/test_validation.py
@@ -1,4 +1,8 @@
from connexion.decorators.validation import ParameterValidator
from jsonschema import ValidationError

import pytest
from connexion.decorators.validation import (Draft4ValidatorSupportNullable,
ParameterValidator)
from mock import MagicMock


Expand Down Expand Up @@ -46,3 +50,32 @@ def test_invalid_type_value_error(monkeypatch):
value = {'test': 1, 'second': 2}
result = ParameterValidator.validate_parameter('formdata', value, {'type': 'boolean', 'name': 'foo'})
assert result == "Wrong type, expected 'boolean' for formdata parameter 'foo'"

def test_support_nullable_properties():
schema = {
"type": "object",
"properties": {"foo": {"type": "string", "x-nullable": True}},
}
try:
Draft4ValidatorSupportNullable(schema).validate({"foo": None})
except ValidationError:
pytest.fail("Shouldn't raise ValidationError")


def test_support_nullable_properties_raises_validation_error():
schema = {
"type": "object",
"properties": {"foo": {"type": "string", "x-nullable": False}},
}

with pytest.raises(ValidationError):
Draft4ValidatorSupportNullable(schema).validate({"foo": None})


def test_support_nullable_properties_not_iterable():
schema = {
"type": "object",
"properties": {"foo": {"type": "string", "x-nullable": True}},
}
with pytest.raises(ValidationError):
Draft4ValidatorSupportNullable(schema).validate(12345)

0 comments on commit 86b5059

Please sign in to comment.