Data Models¶
flaskdoc introspects native python objects and converts then into swagger appropriate json schema. Data models can be defined using either standard python classes, dataclasses or attrs. Flaskdoc will automatically convert them into json schema.
Schema from Python Classes¶
Note
For native python classes like the example above, default values are used to decipher the types, else it defaults to string. Finer control over types can be achieved using either python data classes or attrs or type annotations
from flaskdoc.schema import SchemaFactory
class OakTown:
""" Sample class without any special annotations """
oaks = None
smugs = 1 # type: int
snux = "2" # type: str
factory = SchemaFactory()
schema = factory.get_schema(OakTown)
print(schema.json())
# {'$ref': '#/components/schemas/OakTown', 'description': 'Sample class without any special annotations '}
print(factory.schemas['OakTown'])
# {
# "properties": {
# "oaks": {
# "type": "string"
# },
# "smugs": {
# "type": "integer"
# },
# "snux": {
# "type": "string"
# }
# },
# "type": "object"
# }
Schema using typing module¶
An example schema two array properties samples
and squeezes
and an integer property density
class SoakedBean(object):
density: int = None
samples: List[Sample] = []
squeezes: Set[Squeezed] = {}
Schema using attr classes¶
Note
With attr
types are deciphered using the type
parameter of attr.ib
if available, else if defaults to the
type of the default value. If that is also not available it defaults to string.
from typing import List, Set
@attr.s
class Sample(object):
""" Class with mixed attribute definitions """
danni = "fear"
palo = attr.ib(type=int)
soap = attr.ib(type=SoapStar)
hulu = attr.ib(default="NoNo")
class Squeezed:
""" Sample class with typed annotations """
sample = 1
spaces = 6
class SoakedBean(object):
density: int = None
samples: List[Sample] = []
squeezes: Set[Squeezed] = {}
schema = factory.get_schema(SoakedBean)
print(schema.json())
# {"$ref": "#/components/schemas/SoakedBean"}
print(factory.schemas['SoakedBean'])
# {
# "properties": {
# "density": {
# "type": "integer",
# "format": "int32"
# },
# "samples": {
# "items": {
# "$ref": "#/components/schemas/Sample",
# "description": "Class with mixed attribute definitions "
# },
# "type": "array"
# },
# "squeezes": {
# "items": {
# "$ref": "#/components/schemas/Squeezed",
# "description": "Sample class with typed annotations "
# },
# "type": "array"
# }
# },
# "type": "object"
# }
print(factory.schemas['Sample'])
# {
# "properties": {
# "palo": {
# "type": "integer",
# "format": "int32"
# },
# "soap": {
# "$ref": "#/components/schemas/SoapStar",
# "description": "Simple attr based class "
# },
# "hulu": {
# "type": "string"
# },
# "danni": {
# "type": "string"
# }
# },
# "type": "object"
# }
Schema with dataclasses (>=py3.7)¶
@dataclass
class SoakedBean(object):
density: int = None
samples: List[Sample] = []
squeezes: Set[Squeezed] = {}
jo (json objects) models¶
Note
A drawback with defining schemas using the techniques described above is that there is no way to specify property constraints, eg max value for ints or minlength for strings.
jo is part of flaskdoc builtin functions that allows for adding constraints to native python classes. It makes it possible to define complex json schema representation from simple/plain/native python data types. It wraps around attr to enable developer provided schema constraints to properties in classes.
from flaskdoc import jo
@jo.schema(xml="SoakedBean")
class SoakedBean(object):
density = jo.integer(default=10, minimum=9, maximum=10)
samples = jo.array(item=Sample, min_items=1, xml="Samples")
squeezes = jo.array(item=Squeezed, min_items=1, unique_items=True, xml="Squeezes")
# models can be used as normal data objects
bean = SoakedBean(density=12, samples=[Sample()], squeezes=[Squeezed()])
Model properties can be automatically converted to camel case by setting the camel_case_fields property of jo.schema .. automodule:: flaskdoc.jo
- members