Merge pull request #293 from p1c2u/feature/docs

Basic documentation
This commit is contained in:
A 2021-02-14 15:35:57 +00:00 committed by GitHub
commit 4e7d8edbb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 561 additions and 299 deletions

View file

@ -31,4 +31,10 @@ reports-cleanup:
test-cleanup: test-cache-cleanup reports-cleanup test-cleanup: test-cache-cleanup reports-cleanup
docs-html:
sphinx-build -b html docs docs/_build
docs-cleanup:
@rm -rf docs/_build
cleanup: dist-cleanup test-cleanup cleanup: dist-cleanup test-cleanup

View file

@ -19,7 +19,24 @@ About
##### #####
Openapi-core is a Python library that adds client-side and server-side support Openapi-core is a Python library that adds client-side and server-side support
for the `OpenAPI Specification v3.0.0 <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md>`__. for the `OpenAPI Specification v3 <https://github.com/OAI/OpenAPI-Specification>`__.
Key features
************
* **Validation** of requests and responses
* Schema **casting** and **unmarshalling**
* Media type and parameters **deserialization**
* **Security** providers (API keys, Cookie, Basic and Bearer HTTP authentications)
* Custom **deserializers** and **formats**
* **Integration** with libraries and frameworks
Documentation
#############
Check documentation to see more details about the features. All documentation is in the "docs" directory and online at `openapi-core.readthedocs.io <https://openapi-core.readthedocs.io>`__
Installation Installation
############ ############
@ -81,7 +98,7 @@ and unmarshal request data from validation result
# get security data # get security data
validated_security = result.security validated_security = result.security
Request object should be instance of OpenAPIRequest class (See `Integrations`_). Request object should be instance of OpenAPIRequest class (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
Response Response
******** ********
@ -111,303 +128,7 @@ and unmarshal response data from validation result
# get data # get data
validated_data = result.data validated_data = result.data
Response object should be instance of OpenAPIResponse class (See `Integrations`_). Response object should be instance of OpenAPIResponse class (See `Integrations <https://openapi-core.readthedocs.io/en/latest/integrations.html>`__).
Security
********
openapi-core supports security for authentication and authorization process. Security data for security schemas are accessible from `security` attribute of `RequestValidationResult` object.
For given security specification:
.. code-block:: yaml
security:
- BasicAuth: []
- ApiKeyAuth: []
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
you can access your security data the following:
.. code-block:: python
result = validator.validate(request)
# get basic auth decoded credentials
result.security['BasicAuth']
# get api key
result.security['ApiKeyAuth']
Supported security types:
* http for Basic and Bearer HTTP authentications schemes
* apiKey for API keys and cookie authentication
Customizations
##############
Spec validation
***************
By default, spec dict is validated on spec creation time. Disabling the validation can improve the performance.
.. code-block:: python
from openapi_core import create_spec
spec = create_spec(spec_dict, validate_spec=False)
Deserializers
*************
Pass custom defined media type deserializers dictionary with supported mimetypes as a key to `RequestValidator` or `ResponseValidator` constructor:
.. code-block:: python
def protobuf_deserializer(message):
feature = route_guide_pb2.Feature()
feature.ParseFromString(message)
return feature
custom_media_type_deserializers = {
'application/protobuf': protobuf_deserializer,
}
validator = ResponseValidator(
spec, custom_media_type_deserializers=custom_media_type_deserializers)
result = validator.validate(request, response)
Formats
*******
OpenAPI defines a ``format`` keyword that hints at how a value should be interpreted, e.g. a ``string`` with the type ``date`` should conform to the RFC 3339 date format.
Openapi-core comes with a set of built-in formatters, but it's also possible to add support for custom formatters for `RequestValidator` and `ResponseValidator`.
Here's how you could add support for a ``usdate`` format that handles dates of the form MM/DD/YYYY:
.. code-block:: python
from datetime import datetime
import re
class USDateFormatter:
def validate(self, value) -> bool:
return bool(re.match(r"^\d{1,2}/\d{1,2}/\d{4}$", value))
def unmarshal(self, value):
return datetime.strptime(value, "%m/%d/%y").date
custom_formatters = {
'usdate': USDateFormatter(),
}
validator = ResponseValidator(spec, custom_formatters=custom_formatters)
result = validator.validate(request, response)
Integrations
############
Django
******
For Django 2.2 you can use DjangoOpenAPIRequest a Django request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.django import DjangoOpenAPIRequest
openapi_request = DjangoOpenAPIRequest(django_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use DjangoOpenAPIResponse as a Django response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.django import DjangoOpenAPIResponse
openapi_response = DjangoOpenAPIResponse(django_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Falcon
******
This section describes integration with `Falcon <https://falconframework.org>`__ web framework.
Middleware
==========
Falcon API can be integrated by `FalconOpenAPIMiddleware` middleware.
.. code-block:: python
from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware
openapi_middleware = FalconOpenAPIMiddleware.from_spec(spec)
api = falcon.API(middleware=[openapi_middleware])
Low level
=========
For Falcon you can use FalconOpenAPIRequest a Falcon request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.falcon import FalconOpenAPIRequestFactory
openapi_request = FalconOpenAPIRequestFactory.create(falcon_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use FalconOpenAPIResponse as a Falcon response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.falcon import FalconOpenAPIResponseFactory
openapi_response = FalconOpenAPIResponseFactory.create(falcon_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Flask
*****
Decorator
=========
Flask views can be integrated by `FlaskOpenAPIViewDecorator` decorator.
.. code-block:: python
from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
openapi = FlaskOpenAPIViewDecorator.from_spec(spec)
@app.route('/home')
@openapi
def home():
pass
If you want to decorate class based view you can use the decorators attribute:
.. code-block:: python
class MyView(View):
decorators = [openapi]
View
====
As an alternative to the decorator-based integration, Flask method based views can be integrated by inheritance from `FlaskOpenAPIView` class.
.. code-block:: python
from openapi_core.contrib.flask.views import FlaskOpenAPIView
class MyView(FlaskOpenAPIView):
pass
app.add_url_rule('/home', view_func=MyView.as_view('home', spec))
Request parameters
==================
In Flask, all unmarshalled request data are provided as Flask request object's openapi.parameters attribute
.. code-block:: python
from flask.globals import request
@app.route('/browse/<id>/')
@openapi
def home():
browse_id = request.openapi.parameters.path['id']
page = request.openapi.parameters.query.get('page', 1)
Low level
=========
You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.flask import FlaskOpenAPIRequest
openapi_request = FlaskOpenAPIRequest(flask_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use FlaskOpenAPIResponse as a Flask/Werkzeug response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.flask import FlaskOpenAPIResponse
openapi_response = FlaskOpenAPIResponse(flask_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Pyramid
*******
See `pyramid_openapi3 <https://github.com/niteoweb/pyramid_openapi3>`_ project.
Bottle
*******
See `bottle-openapi-3 <https://github.com/cope-systems/bottle-openapi-3>`_ project.
Requests
********
This section describes integration with `Requests <https://requests.readthedocs.io>`__ library.
Low level
=========
For Requests you can use RequestsOpenAPIRequest a Requests request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.requests import RequestsOpenAPIRequest
openapi_request = RequestsOpenAPIRequest(requests_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use RequestsOpenAPIResponse as a Requests response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.requests import RequestsOpenAPIResponse
openapi_response = RequestsOpenAPIResponse(requests_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Related projects Related projects
################ ################

61
docs/conf.py Normal file
View file

@ -0,0 +1,61 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import openapi_core
# -- Project information -----------------------------------------------------
project = 'openapi-core'
copyright = '2021, Artur Maciag'
author = 'Artur Maciag'
# The full version, including alpha/beta/rc tags
release = openapi_core.__version__
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.intersphinx",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

65
docs/customizations.rst Normal file
View file

@ -0,0 +1,65 @@
Customizations
==============
Spec validation
---------------
By default, spec dict is validated on spec creation time. Disabling the validation can improve the performance.
.. code-block:: python
from openapi_core import create_spec
spec = create_spec(spec_dict, validate_spec=False)
Deserializers
-------------
Pass custom defined media type deserializers dictionary with supported mimetypes as a key to `RequestValidator` or `ResponseValidator` constructor:
.. code-block:: python
def protobuf_deserializer(message):
feature = route_guide_pb2.Feature()
feature.ParseFromString(message)
return feature
custom_media_type_deserializers = {
'application/protobuf': protobuf_deserializer,
}
validator = ResponseValidator(
spec, custom_media_type_deserializers=custom_media_type_deserializers)
result = validator.validate(request, response)
Formats
-------
OpenAPI defines a ``format`` keyword that hints at how a value should be interpreted, e.g. a ``string`` with the type ``date`` should conform to the RFC 3339 date format.
Openapi-core comes with a set of built-in formatters, but it's also possible to add support for custom formatters for `RequestValidator` and `ResponseValidator`.
Here's how you could add support for a ``usdate`` format that handles dates of the form MM/DD/YYYY:
.. code-block:: python
from datetime import datetime
import re
class USDateFormatter:
def validate(self, value) -> bool:
return bool(re.match(r"^\d{1,2}/\d{1,2}/\d{4}$", value))
def unmarshal(self, value):
return datetime.strptime(value, "%m/%d/%y").date
custom_formatters = {
'usdate': USDateFormatter(),
}
validator = ResponseValidator(spec, custom_formatters=custom_formatters)
result = validator.validate(request, response)

43
docs/index.rst Normal file
View file

@ -0,0 +1,43 @@
.. openapi-core documentation master file, created by
sphinx-quickstart on Tue Feb 2 17:41:34 2021.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to openapi-core's documentation!
========================================
Openapi-core is a Python library that adds client-side and server-side support
for the `OpenAPI Specification v3 <https://github.com/OAI/OpenAPI-Specification>`__.
Key features
------------
* **Validation** of requests and responses
* Schema **casting** and **unmarshalling**
* Media type and parameters **deserialization**
* **Security** providers (API keys, Cookie, Basic and Bearer HTTP authentications)
* Custom **deserializers** and **formats**
* **Integration** with libraries and frameworks
Table of contents
-----------------
.. Navigation/TOC
.. toctree::
:maxdepth: 2
installation
usage
customizations
integrations
Related projects
================
* `openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`__
Python library that validates OpenAPI Specs against the OpenAPI 2.0 (aka Swagger) and OpenAPI 3.0.0 specification. The validator aims to check for full compliance with the Specification.
* `openapi-schema-validator <https://github.com/p1c2u/openapi-schema-validator>`__
Python library that validates schema against the OpenAPI Schema Specification v3.0 which is an extended subset of the JSON Schema Specification Wright Draft 00.

15
docs/installation.rst Normal file
View file

@ -0,0 +1,15 @@
Installation
============
Recommended way (via pip):
.. code-block:: console
$ pip install openapi-core
Alternatively you can download the code and install from the repository:
.. code-block:: console
$ pip install -e git+https://github.com/p1c2u/openapi-core.git#egg=openapi_core

198
docs/integrations.rst Normal file
View file

@ -0,0 +1,198 @@
Integrations
============
Bottle
------
See `bottle-openapi-3 <https://github.com/cope-systems/bottle-openapi-3>`_ project.
Django
------
This section describes integration with `Django <https://www.djangoproject.com>`__ web framework.
For Django 2.2 you can use DjangoOpenAPIRequest a Django request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.django import DjangoOpenAPIRequest
openapi_request = DjangoOpenAPIRequest(django_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use DjangoOpenAPIResponse as a Django response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.django import DjangoOpenAPIResponse
openapi_response = DjangoOpenAPIResponse(django_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Falcon
------
This section describes integration with `Falcon <https://falconframework.org>`__ web framework.
Middleware
~~~~~~~~~~
Falcon API can be integrated by `FalconOpenAPIMiddleware` middleware.
.. code-block:: python
from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware
openapi_middleware = FalconOpenAPIMiddleware.from_spec(spec)
api = falcon.API(middleware=[openapi_middleware])
Low level
~~~~~~~~~
For Falcon you can use FalconOpenAPIRequest a Falcon request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.falcon import FalconOpenAPIRequestFactory
openapi_request = FalconOpenAPIRequestFactory.create(falcon_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use FalconOpenAPIResponse as a Falcon response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.falcon import FalconOpenAPIResponseFactory
openapi_response = FalconOpenAPIResponseFactory.create(falcon_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Flask
-----
This section describes integration with `Flask <https://flask.palletsprojects.com>`__ web framework.
Decorator
~~~~~~~~~
Flask views can be integrated by `FlaskOpenAPIViewDecorator` decorator.
.. code-block:: python
from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
openapi = FlaskOpenAPIViewDecorator.from_spec(spec)
@app.route('/home')
@openapi
def home():
pass
If you want to decorate class based view you can use the decorators attribute:
.. code-block:: python
class MyView(View):
decorators = [openapi]
View
~~~~
As an alternative to the decorator-based integration, Flask method based views can be integrated by inheritance from `FlaskOpenAPIView` class.
.. code-block:: python
from openapi_core.contrib.flask.views import FlaskOpenAPIView
class MyView(FlaskOpenAPIView):
pass
app.add_url_rule('/home', view_func=MyView.as_view('home', spec))
Request parameters
~~~~~~~~~~~~~~~~~~
In Flask, all unmarshalled request data are provided as Flask request object's openapi.parameters attribute
.. code-block:: python
from flask.globals import request
@app.route('/browse/<id>/')
@openapi
def home():
browse_id = request.openapi.parameters.path['id']
page = request.openapi.parameters.query.get('page', 1)
Low level
~~~~~~~~~
You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.flask import FlaskOpenAPIRequest
openapi_request = FlaskOpenAPIRequest(flask_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use FlaskOpenAPIResponse as a Flask/Werkzeug response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.flask import FlaskOpenAPIResponse
openapi_response = FlaskOpenAPIResponse(flask_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)
Pyramid
-------
See `pyramid_openapi3 <https://github.com/niteoweb/pyramid_openapi3>`_ project.
Requests
--------
This section describes integration with `Requests <https://requests.readthedocs.io>`__ library.
Low level
~~~~~~~~~
For Requests you can use RequestsOpenAPIRequest a Requests request factory:
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
from openapi_core.contrib.requests import RequestsOpenAPIRequest
openapi_request = RequestsOpenAPIRequest(requests_request)
validator = RequestValidator(spec)
result = validator.validate(openapi_request)
You can use RequestsOpenAPIResponse as a Requests response factory:
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
from openapi_core.contrib.requests import RequestsOpenAPIResponse
openapi_response = RequestsOpenAPIResponse(requests_response)
validator = ResponseValidator(spec)
result = validator.validate(openapi_request, openapi_response)

35
docs/make.bat Normal file
View file

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

2
docs/requirements.txt Normal file
View file

@ -0,0 +1,2 @@
sphinx
sphinx_rtd_theme

116
docs/usage.rst Normal file
View file

@ -0,0 +1,116 @@
Usage
=====
Firstly create your specification:
.. code-block:: python
from openapi_core import create_spec
spec = create_spec(spec_dict)
Request
-------
Now you can use it to validate requests
.. code-block:: python
from openapi_core.validation.request.validators import RequestValidator
validator = RequestValidator(spec)
result = validator.validate(request)
# raise errors if request invalid
result.raise_for_errors()
# get list of errors
errors = result.errors
and unmarshal request data from validation result
.. code-block:: python
# get parameters object with path, query, cookies and headers parameters
validated_params = result.parameters
# or specific parameters
validated_path_params = result.parameters.path
# get body
validated_body = result.body
# get security data
validated_security = result.security
Request object should be instance of OpenAPIRequest class (See :doc:`integrations`).
Response
--------
You can also validate responses
.. code-block:: python
from openapi_core.validation.response.validators import ResponseValidator
validator = ResponseValidator(spec)
result = validator.validate(request, response)
# raise errors if response invalid
result.raise_for_errors()
# get list of errors
errors = result.errors
and unmarshal response data from validation result
.. code-block:: python
# get headers
validated_headers = result.headers
# get data
validated_data = result.data
Response object should be instance of OpenAPIResponse class (See :doc:`integrations`).
Security
--------
openapi-core supports security for authentication and authorization process. Security data for security schemas are accessible from `security` attribute of `RequestValidationResult` object.
For given security specification:
.. code-block:: yaml
security:
- BasicAuth: []
- ApiKeyAuth: []
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
you can access your security data the following:
.. code-block:: python
result = validator.validate(request)
# get basic auth decoded credentials
result.security['BasicAuth']
# get api key
result.security['ApiKeyAuth']
Supported security types:
* http for Basic and Bearer HTTP authentications schemes
* apiKey for API keys and cookie authentication