Welcome to openapi-core’s documentation!
Openapi-core is a Python library that adds client-side and server-side support for the OpenAPI v3.0 and OpenAPI v3.1 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
Installation
Recommended way (via pip):
$ pip install openapi-core
Alternatively you can download the code and install from the repository:
$ pip install -e git+https://github.com/p1c2u/openapi-core.git#egg=openapi_core
Usage
Firstly create your specification object. By default, OpenAPI spec version is detected:
from json import load
from openapi_core import Spec
with open('openapi.json', 'r') as spec_file:
spec_dict = load(spec_file)
spec = Spec.create(spec_dict)
Request
Now you can use it to validate against requests
from openapi_core import openapi_request_validator
result = openapi_request_validator.validate(spec, request)
# raise errors if request invalid
result.raise_for_errors()
# get list of errors
errors = result.errors
and unmarshal request data from validation result
# get parameters object with path, query, cookies and headers parameters
validated_params = result.parameters
# or specific location parameters
validated_path_params = result.parameters.path
# get body
validated_body = result.body
# get security data
validated_security = result.security
Request object should implement OpenAPI Request protocol (See Integrations).
Response
You can also validate against responses
from openapi_core import openapi_response_validator
result = openapi_response_validator.validate(spec, 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
# get headers
validated_headers = result.headers
# get data
validated_data = result.data
Response object should implement OpenAPI Response protocol (See 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:
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:
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
Integrations
Bottle
See bottle-openapi-3 project.
Django
This section describes integration with Django web framework. The integration supports Django from version 3.0 and above.
Middleware
Django can be integrated by middleware. Add DjangoOpenAPIMiddleware
to your MIDDLEWARE
list and define OPENAPI_SPEC
.
# settings.py
from openapi_core import Spec
MIDDLEWARE = [
# ...
'openapi_core.contrib.django.middlewares.DjangoOpenAPIMiddleware',
]
OPENAPI_SPEC = Spec.create(spec_dict)
After that you have access to validation result object with all validated request data from Django view through request object.
from django.views import View
class MyView(View):
def get(self, req):
# get parameters object with path, query, cookies and headers parameters
validated_params = req.openapi.parameters
# or specific location parameters
validated_path_params = req.openapi.parameters.path
# get body
validated_body = req.openapi.body
# get security data
validated_security = req.openapi.security
Low level
You can use DjangoOpenAPIRequest
as a Django request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.django import DjangoOpenAPIRequest
openapi_request = DjangoOpenAPIRequest(django_request)
result = openapi_request_validator.validate(spec, openapi_request)
You can use DjangoOpenAPIResponse
as a Django response factory:
from openapi_core import openapi_response_validator
from openapi_core.contrib.django import DjangoOpenAPIResponse
openapi_response = DjangoOpenAPIResponse(django_response)
result = openapi_response_validator.validate(spec, openapi_request, openapi_response)
Falcon
This section describes integration with Falcon web framework. The integration supports Falcon from version 3.0 and above.
Middleware
The Falcon API can be integrated by FalconOpenAPIMiddleware
middleware.
from openapi_core.contrib.falcon.middlewares import FalconOpenAPIMiddleware
openapi_middleware = FalconOpenAPIMiddleware.from_spec(spec)
app = falcon.App(middleware=[openapi_middleware])
After that you will have access to validation result object with all validated request data from Falcon view through request context.
class ThingsResource:
def on_get(self, req, resp):
# get parameters object with path, query, cookies and headers parameters
validated_params = req.context.openapi.parameters
# or specific location parameters
validated_path_params = req.context.openapi.parameters.path
# get body
validated_body = req.context.openapi.body
# get security data
validated_security = req.context.openapi.security
Low level
You can use FalconOpenAPIRequest
as a Falcon request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.falcon import FalconOpenAPIRequest
openapi_request = FalconOpenAPIRequest(falcon_request)
result = openapi_request_validator.validate(spec, openapi_request)
You can use FalconOpenAPIResponse
as a Falcon response factory:
from openapi_core import openapi_response_validator
from openapi_core.contrib.falcon import FalconOpenAPIResponse
openapi_response = FalconOpenAPIResponse(falcon_response)
result = openapi_response_validator.validate(spec, openapi_request, openapi_response)
Flask
This section describes integration with Flask web framework.
Decorator
Flask views can be integrated by FlaskOpenAPIViewDecorator
decorator.
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:
class MyView(View):
decorators = [openapi]
View
As an alternative to the decorator-based integration, a Flask method based views can be integrated by inheritance from FlaskOpenAPIView
class.
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
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
as a Flask request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.flask import FlaskOpenAPIRequest
openapi_request = FlaskOpenAPIRequest(flask_request)
result = openapi_request_validator.validate(spec, openapi_request)
For response factory see Werkzeug integration.
Pyramid
See pyramid_openapi3 project.
Requests
This section describes integration with Requests library.
Low level
You can use RequestsOpenAPIRequest
as a Requests request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.requests import RequestsOpenAPIRequest
openapi_request = RequestsOpenAPIRequest(requests_request)
result = openapi_request_validator.validate(spec, openapi_request)
You can use RequestsOpenAPIResponse
as a Requests response factory:
from openapi_core import openapi_response_validator
from openapi_core.contrib.requests import RequestsOpenAPIResponse
openapi_response = RequestsOpenAPIResponse(requests_response)
result = openapi_response_validator.validate(spec, openapi_request, openapi_response)
Starlette
This section describes integration with Starlette ASGI framework.
Low level
You can use StarletteOpenAPIRequest
as a Starlette request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.starlette import StarletteOpenAPIRequest
openapi_request = StarletteOpenAPIRequest(starlette_request)
result = openapi_request_validator.validate(spec, openapi_request)
You can use StarletteOpenAPIResponse
as a Starlette response factory:
from openapi_core import openapi_response_validator
from openapi_core.contrib.starlette import StarletteOpenAPIResponse
openapi_response = StarletteOpenAPIResponse(starlette_response)
result = openapi_response_validator.validate(spec, openapi_request, openapi_response)
Tornado
See tornado-openapi3 project.
Werkzeug
This section describes integration with Werkzeug a WSGI web application library.
Low level
You can use WerkzeugOpenAPIRequest
as a Werkzeug request factory:
from openapi_core import openapi_request_validator
from openapi_core.contrib.werkzeug import WerkzeugOpenAPIRequest
openapi_request = WerkzeugOpenAPIRequest(werkzeug_request)
result = openapi_request_validator.validate(spec, openapi_request)
You can use WerkzeugOpenAPIResponse
as a Werkzeug response factory:
from openapi_core import openapi_response_validator
from openapi_core.contrib.werkzeug import WerkzeugOpenAPIResponse
openapi_response = WerkzeugOpenAPIResponse(werkzeug_response)
result = openapi_response_validator.validate(spec, openapi_request, openapi_response)
Customizations
Spec validation
By default, spec dict is validated on spec creation time. Disabling the validator can improve the performance.
from openapi_core import Spec
spec = Spec.create(spec_dict, validator=None)
Deserializers
Pass custom defined media type deserializers dictionary with supported mimetypes as a key to MediaTypeDeserializersFactory and then pass it to RequestValidator or ResponseValidator constructor:
from openapi_core.deserializing.media_types.factories import MediaTypeDeserializersFactory
from openapi_core.unmarshalling.schemas import oas30_response_schema_unmarshallers_factory
def protobuf_deserializer(message):
feature = route_guide_pb2.Feature()
feature.ParseFromString(message)
return feature
custom_media_type_deserializers = {
'application/protobuf': protobuf_deserializer,
}
media_type_deserializers_factory = MediaTypeDeserializersFactory(
custom_deserializers=custom_media_type_deserializers,
)
validator = ResponseValidator(
oas30_response_schema_unmarshallers_factory,
media_type_deserializers_factory=media_type_deserializers_factory,
)
result = validator.validate(spec, 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 custom formatters in SchemaUnmarshallersFactory and pass it to RequestValidator or ResponseValidator.
Here’s how you could add support for a usdate
format that handles dates of the form MM/DD/YYYY:
from openapi_core.unmarshalling.schemas.factories import SchemaUnmarshallersFactory
from openapi_schema_validator import OAS30Validator
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 format(self, value):
return datetime.strptime(value, "%m/%d/%y").date
custom_formatters = {
'usdate': USDateFormatter(),
}
schema_unmarshallers_factory = SchemaUnmarshallersFactory(
OAS30Validator,
custom_formatters=custom_formatters,
context=UnmarshalContext.RESPONSE,
)
validator = ResponseValidator(schema_unmarshallers_factory)
result = validator.validate(spec, request, response)
Extensions
x-model
By default, objects are unmarshalled to dictionaries. You can use dynamically created dataclasses.
...
components:
schemas:
Coordinates:
x-model: Coordinates
type: object
required:
- lat
- lon
properties:
lat:
type: number
lon:
type: number
You can use your own dataclasses, pydantic models or models generated by third party generators (i.e. datamodel-code-generator) by providing x-model-path
property inside schema definition with location of your class.
...
components:
schemas:
Coordinates:
x-model-path: foo.bar.Coordinates
type: object
required:
- lat
- lon
properties:
lat:
type: number
lon:
type: number
# foo/bar.py
from dataclasses import dataclass
@dataclass
class Coordinates:
lat: float
lon: float