Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ Bug Fixes
::

* Add python version requirement on setup.py (#586) [jason-the-j]
* Fix Nested field schema generation for nullable fields. (#638) [peter-doggart]
* Fix reference resolution for definitions in schema. (#553) [peter-doggart]


.. _section-1.3.0:
1.3.0
-----
Expand Down
18 changes: 18 additions & 0 deletions flask_restx/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ class Raw(object):
:param bool readonly: Is the field read only ? (for documentation purpose)
:param example: An optional data example (for documentation purpose)
:param callable mask: An optional mask function to be applied to output
:param bool nullable: Whether the field accepts null values in input
validation. When True, the generated JSON Schema will allow null
values for this field during request payload validation.
"""

#: The JSON/Swagger schema type
Expand All @@ -153,6 +156,7 @@ def __init__(
readonly=None,
example=None,
mask=None,
nullable=None,
**kwargs
):
self.attribute = attribute
Expand All @@ -163,6 +167,7 @@ def __init__(
self.readonly = readonly
self.example = example if example is not None else self.__schema_example__
self.mask = mask
self.nullable = nullable

def format(self, value):
"""
Expand Down Expand Up @@ -284,6 +289,19 @@ def schema(self):
schema["allOf"] = allOf
else:
schema["$ref"] = ref

# If nullable is True, wrap using anyOf to permit nulls for input validation
if self.nullable:
# Remove structural keys that conflict with anyOf composition
for key in ("$ref", "allOf", "type", "items"):
schema.pop(key, None)
# Create anyOf with the original schema and null type
anyOf = [{"$ref": ref}]
if self.as_list:
anyOf = [{"type": "array", "items": {"$ref": ref}}]
anyOf.append({"type": "null"})
schema["anyOf"] = anyOf

return schema

def clone(self, mask=None):
Expand Down
11 changes: 11 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,17 @@ def test_with_allow_null(self, api):
assert field.allow_null
assert field.__schema__ == {"$ref": "#/definitions/NestedModel"}

def test_with_nullable_schema(self, api):
nested_fields = api.model("NestedModel", {"name": fields.String})
field = fields.Nested(nested_fields, nullable=True)
# Should allow null in schema via anyOf
assert field.__schema__ == {
"anyOf": [
{"$ref": "#/definitions/NestedModel"},
{"type": "null"},
]
}

def test_with_skip_none(self, api):
nested_fields = api.model("NestedModel", {"name": fields.String})
field = fields.Nested(nested_fields, skip_none=True)
Expand Down