Skip to content

Commit

Permalink
Allow null option for properties
Browse files Browse the repository at this point in the history
The Swagger specification in version 2 doesn't support 'null' as
property value. This adds a vendor extension 'x-nullable' which
allows properties to be 'null' if set to 'true'.
See OAI/OpenAPI-Specification#229
  • Loading branch information
andreashug committed Jul 22, 2016
1 parent c3b7e74 commit bd39cf0
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
4 changes: 4 additions & 0 deletions bravado_core/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def is_param_spec(swagger_spec, schema_object_spec):
return 'in' in swagger_spec.deref(schema_object_spec)


def is_prop_nullable(swagger_spec, schema_object_spec):
return swagger_spec.deref(schema_object_spec).get('x-nullable', False)


def is_ref(spec):
return is_dict_like(spec) and '$ref' in spec

Expand Down
10 changes: 7 additions & 3 deletions bravado_core/swagger20_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from jsonschema.validators import Draft4Validator

from bravado_core.schema import is_param_spec
from bravado_core.schema import is_prop_nullable
from bravado_core.schema import is_required
from swagger_spec_validator.ref_validators import in_scope

Expand All @@ -18,8 +19,10 @@
def type_validator(swagger_spec, validator, types, instance, schema):
"""Skip the `type` validator when a Swagger parameter value is None.
Otherwise it will fail with a "None is not a valid type" failure instead
of letting the downstream `required_validator` do its job. In all other
cases, delegate to the existing Draft4 `type` validator.
of letting the downstream `required_validator` do its job.
Also skip when a Swagger property value is None and the schema contains
the extension field `x-nullable` set to True.
In all other cases, delegate to the existing Draft4 `type` validator.
:param swagger_spec: needed for access to deref()
:type swagger_spec: :class:`bravado_core.spec.Spec`
Expand All @@ -32,7 +35,8 @@ def type_validator(swagger_spec, validator, types, instance, schema):
:param schema: swagger spec for the object
:type schema: dict
"""
if is_param_spec(swagger_spec, schema) and instance is None:
if (is_param_spec(swagger_spec, schema) or
is_prop_nullable(swagger_spec, schema)) and instance is None:
return

for error in _validators.type_draft4(validator, types, instance, schema):
Expand Down
48 changes: 48 additions & 0 deletions tests/schema/is_prop_nullable_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from bravado_core.schema import is_prop_nullable
from bravado_core.spec import Spec


def test_true(minimal_swagger_spec):
prop_spec = {
'type': 'string',
'x-nullable': True,
}
assert is_prop_nullable(minimal_swagger_spec, prop_spec)


def test_false(minimal_swagger_spec):
prop_spec = {
'type': 'string',
}
assert not is_prop_nullable(minimal_swagger_spec, prop_spec)


def test_false_explicit(minimal_swagger_spec):
prop_spec = {
'type': 'string',
'x-nullable': False,
}
assert not is_prop_nullable(minimal_swagger_spec, prop_spec)


def test_ref_true(minimal_swagger_dict):
minimal_swagger_dict['definitions'] = {
'Pet': {
'type': 'object',
'x-nullable': True,
}
}
param_spec = {'$ref': '#/definitions/Pet'}
swagger_spec = Spec.from_dict(minimal_swagger_dict)
assert is_prop_nullable(swagger_spec, param_spec)


def test_ref_false(minimal_swagger_dict):
minimal_swagger_dict['definitions'] = {
'Pet': {
'type': 'object',
}
}
param_spec = {'$ref': '#/definitions/Pet'}
swagger_spec = Spec.from_dict(minimal_swagger_dict)
assert not is_prop_nullable(swagger_spec, param_spec)
22 changes: 22 additions & 0 deletions tests/swagger20_validator/type_validator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,25 @@ def test_validate_when_not_a_parameter_schema(m_draft4_type_validator,
string_schema)
list(type_validator(minimal_swagger_spec, *args))
m_draft4_type_validator.assert_called_once_with(*args)


@patch('jsonschema._validators.type_draft4')
def test_skip_when_nullable_property_schema_and_value_is_None(
m_draft4_type_validator, minimal_swagger_spec):
param_schema = {'name': 'foo', 'x-nullable': True, 'type': 'string'}
type_validator(
minimal_swagger_spec,
validator=None,
types=param_schema['type'],
instance=None, # property value
schema=param_schema)
assert m_draft4_type_validator.call_count == 0


@patch('jsonschema._validators.type_draft4')
def test_validate_when_not_nullable_property_schema_and_value_is_None(
m_draft4_type_validator, minimal_swagger_spec):
param_schema = {'name': 'foo', 'x-nullable': False, 'type': 'string'}
args = (None, param_schema['type'], None, param_schema)
type_validator(minimal_swagger_spec, *args)
m_draft4_type_validator.assert_called_once_with(*args)

0 comments on commit bd39cf0

Please sign in to comment.