Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/s-knibbs/dataclasses-jsonschema

JSON schema generation from dataclasses
https://github.com/s-knibbs/dataclasses-jsonschema

dataclasses deserialization jsonschema openapi python serialization type-hints validation

Last synced: about 2 months ago
JSON representation

JSON schema generation from dataclasses

Awesome Lists containing this project

README

        

Dataclasses JSON Schema
=======================

.. image:: https://github.com/s-knibbs/dataclasses-jsonschema/workflows/Tox%20tests/badge.svg?branch=master
:target: https://github.com/s-knibbs/dataclasses-jsonschema/actions

.. image:: https://badge.fury.io/py/dataclasses-jsonschema.svg
:target: https://badge.fury.io/py/dataclasses-jsonschema

**⚠️Please Note⚠️:** **Because of health reasons I'm not longer able to make changes to this project or make further releases via PyPI.**

A library to generate JSON Schema from python 3.7 dataclasses. Python 3.6 is supported through the `dataclasses backport `_. Aims to be a more lightweight alternative to similar projects such as `marshmallow `_ & `pydantic `_.

Feature Overview
----------------

* Support for draft-04, draft-06, Swagger 2.0 & OpenAPI 3 schema types
* Serialisation and deserialisation
* Data validation against the generated schema
* `APISpec `_ support. Example below_:

Installation
------------

.. code:: bash

~$ pip install dataclasses-jsonschema

For improved validation performance using `fastjsonschema `_, install with:

.. code:: bash

~$ pip install dataclasses-jsonschema[fast-validation]

For improved uuid performance using `fastuuid `_, install with:

.. code:: bash

~$ pip install dataclasses-jsonschema[fast-uuid]

For improved date and datetime parsing performance using `ciso8601 `_, install with:

.. code:: bash

~$ pip install dataclasses-jsonschema[fast-dateparsing]

Beware `ciso8601` doesn’t support the entirety of the ISO 8601 spec, only a popular subset.

Examples
--------

.. code:: python

from dataclasses import dataclass

from dataclasses_jsonschema import JsonSchemaMixin

@dataclass
class Point(JsonSchemaMixin):
"A 2D point"
x: float
y: float

Schema Generation
^^^^^^^^^^^^^^^^^

.. code:: python

>>> pprint(Point.json_schema())
{
'description': 'A 2D point',
'type': 'object',
'properties': {
'x': {'format': 'float', 'type': 'number'},
'y': {'format': 'float', 'type': 'number'}
},
'required': ['x', 'y']
}

Data Serialisation
^^^^^^^^^^^^^^^^^^
.. code:: python

>>> Point(x=3.5, y=10.1).to_dict()
{'x': 3.5, 'y': 10.1}

Deserialisation
^^^^^^^^^^^^^^^

.. code:: python

>>> Point.from_dict({'x': 3.14, 'y': 1.5})
Point(x=3.14, y=1.5)
>>> Point.from_dict({'x': 3.14, y: 'wrong'})
dataclasses_jsonschema.ValidationError: 'wrong' is not of type 'number'

Generating multiple schemas
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: python

from dataclasses_jsonschema import JsonSchemaMixin, SchemaType

@dataclass
class Address(JsonSchemaMixin):
"""Postal Address"""
building: str
street: str
city: str

@dataclass
class Company(JsonSchemaMixin):
"""Company Details"""
name: str
address: Address

>>> pprint(JsonSchemaMixin.all_json_schemas(schema_type=SchemaType.SWAGGER_V3))
{'Address': {'description': 'Postal Address',
'properties': {'building': {'type': 'string'},
'city': {'type': 'string'},
'street': {'type': 'string'}},
'required': ['building', 'street', 'city'],
'type': 'object'},
'Company': {'description': 'Company Details',
'properties': {'address': {'$ref': '#/components/schemas/Address'},
'name': {'type': 'string'}},
'required': ['name', 'address'],
'type': 'object'}}

Custom validation using `NewType `_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: python

from dataclasses_jsonschema import JsonSchemaMixin, FieldEncoder

PhoneNumber = NewType('PhoneNumber', str)

class PhoneNumberField(FieldEncoder):

@property
def json_schema(self):
return {'type': 'string', 'pattern': r'^(\([0-9]{3}\))?[0-9]{3}-[0-9]{4}$'}

JsonSchemaMixin.register_field_encoders({PhoneNumber: PhoneNumberField()})

@dataclass
class Person(JsonSchemaMixin):
name: str
phone_number: PhoneNumber

For more examples `see the tests `_

.. _below:

APISpec Plugin
--------------
**New in v2.5.0**

OpenAPI & Swagger specs can be generated using the apispec plugin:

.. code:: python

from typing import Optional, List
from dataclasses import dataclass

from apispec import APISpec
from apispec_webframeworks.flask import FlaskPlugin
from flask import Flask, jsonify
import pytest

from dataclasses_jsonschema.apispec import DataclassesPlugin
from dataclasses_jsonschema import JsonSchemaMixin

# Create an APISpec
spec = APISpec(
title="Swagger Petstore",
version="1.0.0",
openapi_version="3.0.2",
plugins=[FlaskPlugin(), DataclassesPlugin()],
)


@dataclass
class Category(JsonSchemaMixin):
"""Pet category"""
name: str
id: Optional[int]

@dataclass
class Pet(JsonSchemaMixin):
"""A pet"""
categories: List[Category]
name: str

app = Flask(__name__)

@app.route("/random")
def random_pet():
"""A cute furry animal endpoint.
---
get:
description: Get a random pet
responses:
200:
content:
application/json:
schema: Pet
"""
pet = get_random_pet()
return jsonify(pet.to_dict())

# Dependant schemas (e.g. 'Category') are added automatically
spec.components.schema("Pet", schema=Pet)
with app.test_request_context():
spec.path(view=random_pet)

TODO
----

* Add benchmarks against alternatives such as `pydantic `_ and `marshmallow `_