Tornado OpenAPI 3 request and response validation library.
Find a file
Correl Roush 3de1f9c430 Configure coverage reporting
Require 100% code coverage and report missing lines.
2020-12-04 23:04:14 -05:00
tests Configure Hypothesis profiles 2020-12-04 22:44:22 -05:00
tornado_openapi3 Set stricter mypy parameters 2020-12-04 21:01:22 -05:00
.flake8 Initial commit 2020-09-16 23:04:11 -04:00
.gitignore Add code coverage reporting 2020-11-26 00:13:04 -05:00
.travis.yml Add Travis CI 2020-11-20 12:43:23 -05:00
LICENSE Add license and readme 2020-09-18 00:23:55 -04:00
mypy.ini Set stricter mypy parameters 2020-12-04 21:01:22 -05:00
pyproject.toml Configure coverage reporting 2020-12-04 23:04:14 -05:00
README.rst Add contribution documentation to the README 2020-12-04 22:46:40 -05:00
tox.ini Configure Hypothesis profiles 2020-12-04 22:44:22 -05:00

===================
 Tornado OpenAPI 3
===================

.. image:: https://travis-ci.com/correl/tornado-openapi3.svg?branch=master
    :target: https://travis-ci.com/correl/tornado-openapi3
.. image:: https://codecov.io/gh/correl/tornado-openapi3/branch/master/graph/badge.svg?token=CTYWWDXTL9
    :target: https://codecov.io/gh/correl/tornado-openapi3
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
    :target: https://github.com/psf/black


Tornado OpenAPI 3 request and response validation library.

Provides integration between the `Tornado`_ web framework and `Openapi-core`_
library for validating request and response objects against an `OpenAPI 3`_
specification.

Usage
=====

Adding validation to request handlers
-------------------------------------

.. code:: python

    from openapi_core import create_spec  # type: ignore
    from openapi_core.exceptions import OpenAPIError  # type: ignore
    from openapi_core.deserializing.exceptions import DeserializeError  # type: ignore
    from openapi_core.schema.media_types.exceptions import (  # type: ignore
        InvalidContentType,
    )
    from openapi_core.unmarshalling.schemas.exceptions import ValidateError  # type: ignore
    from tornado.web import RequestHandler
    from tornado_openapi3 import RequestValidator
    import yaml


    class OpenAPIRequestHandler(RequestHandler):
        async def prepare(self) -> None:
            maybe_coro = super().prepare()
            if maybe_coro and asyncio.iscoroutine(maybe_coro):  # pragma: no cover
                await maybe_coro

            spec = create_spec(yaml.safe_load(self.render_string("openapi.yaml")))
            validator = RequestValidator(spec)
            result = validator.validate(self.request)
            try:
                result.raise_for_errors()
            except InvalidContentType:
                self.set_status(415)
                self.finish()
            except (DeserializeError, ValidateError) as e:
                self.set_status(400)
                self.finish()
            except OpenAPIError:
                raise

Validating a response
---------------------

.. code:: python

    from tornado.testing import AsyncHTTPTestCase
    from tornado_openapi3 import ResponseValidator

    from myapplication import create_app, spec


    class TestResponses(AsyncHTTPTestCase):
        def get_app(self) -> Application:
            return create_app()

        def test_status(self) -> None:
            validator = ResponseValidator(spec)
            response = self.fetch("/status")
            result = validator.validate(response)
            result.raise_for_errors()

Contributing
============

Getting Started
---------------

This project uses `Poetry`_ to manage its dependencies. To set up a local
development environment, just run:

.. code:: sh

    poetry install

Formatting Code
---------------

The `Black`_ tool is used by this project to format Python code. It is included
as a development dependency, and should be run on all committed code. To format
code prior to committing it and submitting a PR, run:

.. code:: sh

    poetry run black .

Running Tests
-------------

`pytest`_ is the preferred test runner for this project. It is included as a
development dependency, and is configured to track code coverage, `Flake8`_
style compliance, and `Black`_ code formatting. Tests can be run in your
development environment by running:

.. code:: sh

    poetry run pytest

Additionally, tests can be run using `tox`_, which will run the tests using
multiple versions of both Python and Tornado to ensure broad compatibility.

Configuring Hypothesis
^^^^^^^^^^^^^^^^^^^^^^

Many of the tests make use of `Hypothesis`_ to specify their expectations and
generate a large volume of randomized test input. Because of this, the tests may
take a long time to run on slower computers. Three profiles are defined for
Hypothesis to use which can be selected by setting the ``HYPOTHESIS_PROFILE``
environment variable to one of the following values:

``default``
  Runs tests using the default Hypothesis settings (100 examples per test with a
  default completion deadline)

``dev``
  The fastest profile, meant for local development only. Uses only 10 examples
  per test with no completion deadline.

``ci``
  The slowest profile, used for automated testing. Uses 1000 examples per test,
  with the default completion deadline.

.. _Black: https://github.com/psf/black
.. _Flake8: https://flake8.pycqa.org/
.. _Hypothesis: https://hypothesis.readthedocs.io/
.. _OpenAPI 3: https://swagger.io/specification/
.. _Openapi-core: https://github.com/p1c2u/openapi-core
.. _Poetry: https://python-poetry.org/
.. _Tornado: https://www.tornadoweb.org/
.. _pytest: https://pytest.org/
.. _tox: https://tox.readthedocs.io/