mirror of
https://github.com/correl/openapi-core.git
synced 2025-01-04 03:00:15 +00:00
Merge pull request #167 from p1c2u/feature/django-support
Django OpenAPI request/response factories
This commit is contained in:
commit
fd99117278
10 changed files with 416 additions and 26 deletions
120
README.rst
120
README.rst
|
@ -1,3 +1,4 @@
|
||||||
|
************
|
||||||
openapi-core
|
openapi-core
|
||||||
************
|
************
|
||||||
|
|
||||||
|
@ -15,13 +16,13 @@ openapi-core
|
||||||
:target: https://pypi.python.org/pypi/openapi-core
|
:target: https://pypi.python.org/pypi/openapi-core
|
||||||
|
|
||||||
About
|
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.0.0 <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md>`__.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
============
|
############
|
||||||
|
|
||||||
Recommended way (via pip):
|
Recommended way (via pip):
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ Alternatively you can download the code and install from the repository:
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
=====
|
#####
|
||||||
|
|
||||||
Firstly create your specification:
|
Firstly create your specification:
|
||||||
|
|
||||||
|
@ -47,6 +48,9 @@ Firstly create your specification:
|
||||||
|
|
||||||
spec = create_spec(spec_dict)
|
spec = create_spec(spec_dict)
|
||||||
|
|
||||||
|
Request
|
||||||
|
*******
|
||||||
|
|
||||||
Now you can use it to validate requests
|
Now you can use it to validate requests
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -83,27 +87,10 @@ or use shortcuts for simple validation
|
||||||
validated_params = validate_parameters(spec, request)
|
validated_params = validate_parameters(spec, request)
|
||||||
validated_body = validate_body(spec, request)
|
validated_body = validate_body(spec, request)
|
||||||
|
|
||||||
Request object should be instance of OpenAPIRequest class. You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
|
Request object should be instance of OpenAPIRequest class (See `Integrations`_).
|
||||||
|
|
||||||
.. code-block:: python
|
Response
|
||||||
|
********
|
||||||
from openapi_core.shortcuts import RequestValidator
|
|
||||||
from openapi_core.contrib.flask import FlaskOpenAPIRequest
|
|
||||||
|
|
||||||
openapi_request = FlaskOpenAPIRequest(flask_request)
|
|
||||||
validator = RequestValidator(spec)
|
|
||||||
result = validator.validate(openapi_request)
|
|
||||||
|
|
||||||
or simply specify request factory for shortcuts
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from openapi_core import validate_parameters, validate_body
|
|
||||||
|
|
||||||
validated_params = validate_parameters(
|
|
||||||
spec, request, request_factory=FlaskOpenAPIRequest)
|
|
||||||
validated_body = validate_body(
|
|
||||||
spec, request, request_factory=FlaskOpenAPIRequest)
|
|
||||||
|
|
||||||
You can also validate responses
|
You can also validate responses
|
||||||
|
|
||||||
|
@ -138,7 +125,85 @@ or use shortcuts for simple validation
|
||||||
|
|
||||||
validated_data = validate_data(spec, request, response)
|
validated_data = validate_data(spec, request, response)
|
||||||
|
|
||||||
Response object should be instance of OpenAPIResponse class. You can use FlaskOpenAPIResponse a Flask/Werkzeug response factory:
|
Response object should be instance of OpenAPIResponse class (See `Integrations`_).
|
||||||
|
|
||||||
|
|
||||||
|
Integrations
|
||||||
|
############
|
||||||
|
|
||||||
|
Django
|
||||||
|
******
|
||||||
|
|
||||||
|
For Django 2.2 you can use DjangoOpenAPIRequest a Django request factory:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core.shortcuts import RequestValidator
|
||||||
|
from openapi_core.contrib.django import DjangoOpenAPIRequest
|
||||||
|
|
||||||
|
openapi_request = DjangoOpenAPIRequest(django_request)
|
||||||
|
validator = RequestValidator(spec)
|
||||||
|
result = validator.validate(openapi_request)
|
||||||
|
|
||||||
|
or simply specify request factory for shortcuts
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core import validate_parameters, validate_body
|
||||||
|
|
||||||
|
validated_params = validate_parameters(
|
||||||
|
spec, request, request_factory=DjangoOpenAPIRequest)
|
||||||
|
validated_body = validate_body(
|
||||||
|
spec, request, request_factory=DjangoOpenAPIRequest)
|
||||||
|
|
||||||
|
You can use DjangoOpenAPIResponse as a Django response factory:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core.shortcuts import ResponseValidator
|
||||||
|
from openapi_core.contrib.django import DjangoOpenAPIResponse
|
||||||
|
|
||||||
|
openapi_response = DjangoOpenAPIResponse(django_response)
|
||||||
|
validator = ResponseValidator(spec)
|
||||||
|
result = validator.validate(openapi_request, openapi_response)
|
||||||
|
|
||||||
|
or simply specify response factory for shortcuts
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core import validate_parameters, validate_body
|
||||||
|
|
||||||
|
validated_data = validate_data(
|
||||||
|
spec, request, response,
|
||||||
|
request_factory=DjangoOpenAPIRequest,
|
||||||
|
response_factory=DjangoOpenAPIResponse)
|
||||||
|
|
||||||
|
Flask
|
||||||
|
*****
|
||||||
|
|
||||||
|
You can use FlaskOpenAPIRequest a Flask/Werkzeug request factory:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core.shortcuts import RequestValidator
|
||||||
|
from openapi_core.contrib.flask import FlaskOpenAPIRequest
|
||||||
|
|
||||||
|
openapi_request = FlaskOpenAPIRequest(flask_request)
|
||||||
|
validator = RequestValidator(spec)
|
||||||
|
result = validator.validate(openapi_request)
|
||||||
|
|
||||||
|
or simply specify request factory for shortcuts
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from openapi_core import validate_parameters, validate_body
|
||||||
|
|
||||||
|
validated_params = validate_parameters(
|
||||||
|
spec, request, request_factory=FlaskOpenAPIRequest)
|
||||||
|
validated_body = validate_body(
|
||||||
|
spec, request, request_factory=FlaskOpenAPIRequest)
|
||||||
|
|
||||||
|
You can use FlaskOpenAPIResponse as a Flask/Werkzeug response factory:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -160,7 +225,12 @@ or simply specify response factory for shortcuts
|
||||||
request_factory=FlaskOpenAPIRequest,
|
request_factory=FlaskOpenAPIRequest,
|
||||||
response_factory=FlaskOpenAPIResponse)
|
response_factory=FlaskOpenAPIResponse)
|
||||||
|
|
||||||
|
Pyramid
|
||||||
|
*******
|
||||||
|
|
||||||
|
See `pyramid_openapi3 <https://github.com/niteoweb/pyramid_openapi3>`_ project.
|
||||||
|
|
||||||
Related projects
|
Related projects
|
||||||
================
|
################
|
||||||
* `openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`__
|
* `openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`__
|
||||||
* `pyramid_openapi3 <https://github.com/niteoweb/pyramid_openapi3>`__
|
* `pyramid_openapi3 <https://github.com/niteoweb/pyramid_openapi3>`__
|
||||||
|
|
11
openapi_core/contrib/django/__init__.py
Normal file
11
openapi_core/contrib/django/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
|
||||||
|
from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory
|
||||||
|
|
||||||
|
# backward compatibility
|
||||||
|
DjangoOpenAPIRequest = DjangoOpenAPIRequestFactory.create
|
||||||
|
DjangoOpenAPIResponse = DjangoOpenAPIResponseFactory.create
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'DjangoOpenAPIRequestFactory', 'DjangoOpenAPIResponseFactory',
|
||||||
|
'DjangoOpenAPIRequest', 'DjangoOpenAPIResponse',
|
||||||
|
]
|
51
openapi_core/contrib/django/requests.py
Normal file
51
openapi_core/contrib/django/requests.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
"""OpenAPI core contrib django requests module"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
from openapi_core.validation.request.datatypes import (
|
||||||
|
RequestParameters, OpenAPIRequest,
|
||||||
|
)
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/2.2/topics/http/urls/
|
||||||
|
#
|
||||||
|
# Currently unsupported are :
|
||||||
|
# - nested arguments, e.g.: ^comments/(?:page-(?P<page_number>\d+)/)?$
|
||||||
|
# - unnamed regex groups, e.g.: ^articles/([0-9]{4})/$
|
||||||
|
# - multiple named parameters between a single pair of slashes
|
||||||
|
# e.g.: <page_slug>-<page_id>/edit/
|
||||||
|
#
|
||||||
|
# The regex matches everything, except a "/" until "<". Than only the name
|
||||||
|
# is exported, after which it matches ">" and everything until a "/".
|
||||||
|
PATH_PARAMETER_PATTERN = r'(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)'
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoOpenAPIRequestFactory(object):
|
||||||
|
|
||||||
|
path_regex = re.compile(PATH_PARAMETER_PATTERN)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, request):
|
||||||
|
method = request.method.lower()
|
||||||
|
|
||||||
|
if request.resolver_match is None:
|
||||||
|
path_pattern = request.path
|
||||||
|
else:
|
||||||
|
route = cls.path_regex.sub(
|
||||||
|
r'{\1}', request.resolver_match.route)
|
||||||
|
path_pattern = '/' + route
|
||||||
|
|
||||||
|
path = request.resolver_match and request.resolver_match.kwargs or {}
|
||||||
|
parameters = RequestParameters(
|
||||||
|
path=path,
|
||||||
|
query=request.GET,
|
||||||
|
header=request.headers,
|
||||||
|
cookie=request.COOKIES,
|
||||||
|
)
|
||||||
|
return OpenAPIRequest(
|
||||||
|
host_url=request._current_scheme_host,
|
||||||
|
path=request.path,
|
||||||
|
method=method,
|
||||||
|
path_pattern=path_pattern,
|
||||||
|
parameters=parameters,
|
||||||
|
body=request.body,
|
||||||
|
mimetype=request.content_type,
|
||||||
|
)
|
14
openapi_core/contrib/django/responses.py
Normal file
14
openapi_core/contrib/django/responses.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""OpenAPI core contrib django responses module"""
|
||||||
|
from openapi_core.validation.response.datatypes import OpenAPIResponse
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoOpenAPIResponseFactory(object):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, response):
|
||||||
|
mimetype = response["Content-Type"]
|
||||||
|
return OpenAPIResponse(
|
||||||
|
data=response.content,
|
||||||
|
status_code=response.status_code,
|
||||||
|
mimetype=mimetype,
|
||||||
|
)
|
|
@ -21,6 +21,23 @@ class RequestParameters(object):
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
class OpenAPIRequest(object):
|
class OpenAPIRequest(object):
|
||||||
|
"""OpenAPI request dataclass.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
path
|
||||||
|
Requested path as string.
|
||||||
|
path_pattern
|
||||||
|
The matched url pattern.
|
||||||
|
parameters
|
||||||
|
A RequestParameters object.
|
||||||
|
body
|
||||||
|
The request body, as string.
|
||||||
|
mimetype
|
||||||
|
Like content type, but without parameters (eg, without charset,
|
||||||
|
type etc.) and always lowercase.
|
||||||
|
For example if the content type is "text/HTML; charset=utf-8"
|
||||||
|
the mimetype would be "text/html".
|
||||||
|
"""
|
||||||
|
|
||||||
host_url = attr.ib()
|
host_url = attr.ib()
|
||||||
path = attr.ib()
|
path = attr.ib()
|
||||||
|
|
|
@ -6,6 +6,16 @@ from openapi_core.validation.datatypes import BaseValidationResult
|
||||||
|
|
||||||
@attr.s
|
@attr.s
|
||||||
class OpenAPIResponse(object):
|
class OpenAPIResponse(object):
|
||||||
|
"""OpenAPI request dataclass.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
data
|
||||||
|
The response body, as string.
|
||||||
|
status_code
|
||||||
|
The status code as integer.
|
||||||
|
mimetype
|
||||||
|
Lowercase content type without charset.
|
||||||
|
"""
|
||||||
|
|
||||||
data = attr.ib()
|
data = attr.ib()
|
||||||
status_code = attr.ib()
|
status_code = attr.ib()
|
||||||
|
|
|
@ -2,4 +2,5 @@ mock==2.0.0
|
||||||
pytest==3.5.0
|
pytest==3.5.0
|
||||||
pytest-flake8
|
pytest-flake8
|
||||||
pytest-cov==2.5.1
|
pytest-cov==2.5.1
|
||||||
flask
|
flask
|
||||||
|
django==2.2.6; python_version>="3.0"
|
||||||
|
|
|
@ -43,6 +43,7 @@ exclude =
|
||||||
tests
|
tests
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
|
django = django>=2.2; python_version>="3.0"
|
||||||
flask = werkzeug
|
flask = werkzeug
|
||||||
|
|
||||||
[tool:pytest]
|
[tool:pytest]
|
||||||
|
|
196
tests/integration/contrib/test_django.py
Normal file
196
tests/integration/contrib/test_django.py
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from six import b
|
||||||
|
|
||||||
|
from openapi_core.contrib.django import (
|
||||||
|
DjangoOpenAPIRequest, DjangoOpenAPIResponse,
|
||||||
|
)
|
||||||
|
from openapi_core.shortcuts import create_spec
|
||||||
|
from openapi_core.validation.request.datatypes import RequestParameters
|
||||||
|
from openapi_core.validation.request.validators import RequestValidator
|
||||||
|
from openapi_core.validation.response.validators import ResponseValidator
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.version_info < (3, 0), reason="requires python3")
|
||||||
|
class BaseTestDjango(object):
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True, scope='module')
|
||||||
|
def django_settings(self):
|
||||||
|
import django
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
if settings.configured:
|
||||||
|
return
|
||||||
|
|
||||||
|
settings.configure(
|
||||||
|
ALLOWED_HOSTS=[
|
||||||
|
'testserver',
|
||||||
|
],
|
||||||
|
INSTALLED_APPS=[
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
],
|
||||||
|
MIDDLEWARE=[
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
django.setup()
|
||||||
|
settings.ROOT_URLCONF = (
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def request_factory(self):
|
||||||
|
from django.test.client import RequestFactory
|
||||||
|
return RequestFactory()
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def response_factory(self):
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
def create(content=b(''), status_code=None):
|
||||||
|
return HttpResponse(content, status=status_code)
|
||||||
|
|
||||||
|
return create
|
||||||
|
|
||||||
|
|
||||||
|
class TestDjangoOpenAPIRequest(BaseTestDjango):
|
||||||
|
|
||||||
|
def test_no_resolver(self, request_factory):
|
||||||
|
request = request_factory.get('/admin/')
|
||||||
|
|
||||||
|
openapi_request = DjangoOpenAPIRequest(request)
|
||||||
|
|
||||||
|
path = {}
|
||||||
|
query = {}
|
||||||
|
headers = {
|
||||||
|
'Cookie': '',
|
||||||
|
}
|
||||||
|
cookies = {}
|
||||||
|
assert openapi_request.parameters == RequestParameters(
|
||||||
|
path=path,
|
||||||
|
query=query,
|
||||||
|
header=headers,
|
||||||
|
cookie=cookies,
|
||||||
|
)
|
||||||
|
assert openapi_request.host_url == request._current_scheme_host
|
||||||
|
assert openapi_request.path == request.path
|
||||||
|
assert openapi_request.method == request.method.lower()
|
||||||
|
assert openapi_request.path_pattern == request.path
|
||||||
|
assert openapi_request.body == request.body
|
||||||
|
assert openapi_request.mimetype == request.content_type
|
||||||
|
|
||||||
|
def test_simple(self, request_factory):
|
||||||
|
from django.urls import resolve
|
||||||
|
request = request_factory.get('/admin/')
|
||||||
|
request.resolver_match = resolve('/admin/')
|
||||||
|
|
||||||
|
openapi_request = DjangoOpenAPIRequest(request)
|
||||||
|
|
||||||
|
path = {}
|
||||||
|
query = {}
|
||||||
|
headers = {
|
||||||
|
'Cookie': '',
|
||||||
|
}
|
||||||
|
cookies = {}
|
||||||
|
assert openapi_request.parameters == RequestParameters(
|
||||||
|
path=path,
|
||||||
|
query=query,
|
||||||
|
header=headers,
|
||||||
|
cookie=cookies,
|
||||||
|
)
|
||||||
|
assert openapi_request.host_url == request._current_scheme_host
|
||||||
|
assert openapi_request.path == request.path
|
||||||
|
assert openapi_request.method == request.method.lower()
|
||||||
|
assert openapi_request.path_pattern == request.path
|
||||||
|
assert openapi_request.body == request.body
|
||||||
|
assert openapi_request.mimetype == request.content_type
|
||||||
|
|
||||||
|
def test_url_rule(self, request_factory):
|
||||||
|
from django.urls import resolve
|
||||||
|
request = request_factory.get('/admin/auth/group/1/')
|
||||||
|
request.resolver_match = resolve('/admin/auth/group/1/')
|
||||||
|
|
||||||
|
openapi_request = DjangoOpenAPIRequest(request)
|
||||||
|
|
||||||
|
path = {
|
||||||
|
'object_id': '1',
|
||||||
|
}
|
||||||
|
query = {}
|
||||||
|
headers = {
|
||||||
|
'Cookie': '',
|
||||||
|
}
|
||||||
|
cookies = {}
|
||||||
|
assert openapi_request.parameters == RequestParameters(
|
||||||
|
path=path,
|
||||||
|
query=query,
|
||||||
|
header=headers,
|
||||||
|
cookie=cookies,
|
||||||
|
)
|
||||||
|
assert openapi_request.host_url == request._current_scheme_host
|
||||||
|
assert openapi_request.path == request.path
|
||||||
|
assert openapi_request.method == request.method.lower()
|
||||||
|
assert openapi_request.path_pattern == \
|
||||||
|
"/admin/auth/group/{object_id}/"
|
||||||
|
assert openapi_request.body == request.body
|
||||||
|
assert openapi_request.mimetype == request.content_type
|
||||||
|
|
||||||
|
|
||||||
|
class TestDjangoOpenAPIResponse(BaseTestDjango):
|
||||||
|
|
||||||
|
def test_stream_response(self, response_factory):
|
||||||
|
response = response_factory()
|
||||||
|
response.writelines(['foo\n', 'bar\n', 'baz\n'])
|
||||||
|
|
||||||
|
openapi_response = DjangoOpenAPIResponse(response)
|
||||||
|
|
||||||
|
assert openapi_response.data == b('foo\nbar\nbaz\n')
|
||||||
|
assert openapi_response.status_code == response.status_code
|
||||||
|
assert openapi_response.mimetype == response["Content-Type"]
|
||||||
|
|
||||||
|
def test_redirect_response(self, response_factory):
|
||||||
|
response = response_factory('/redirected/', status_code=302)
|
||||||
|
|
||||||
|
openapi_response = DjangoOpenAPIResponse(response)
|
||||||
|
|
||||||
|
assert openapi_response.data == response.content
|
||||||
|
assert openapi_response.status_code == response.status_code
|
||||||
|
assert openapi_response.mimetype == response["Content-Type"]
|
||||||
|
|
||||||
|
|
||||||
|
class TestDjangoOpenAPIValidation(BaseTestDjango):
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def django_spec(self, factory):
|
||||||
|
specfile = 'data/v3.0/django_factory.yaml'
|
||||||
|
return create_spec(factory.spec_from_file(specfile))
|
||||||
|
|
||||||
|
def test_response_validator_path_pattern(
|
||||||
|
self, django_spec, request_factory, response_factory):
|
||||||
|
from django.urls import resolve
|
||||||
|
validator = ResponseValidator(django_spec)
|
||||||
|
request = request_factory.get('/admin/auth/group/1/')
|
||||||
|
request.resolver_match = resolve('/admin/auth/group/1/')
|
||||||
|
openapi_request = DjangoOpenAPIRequest(request)
|
||||||
|
response = response_factory(b('Some item'))
|
||||||
|
openapi_response = DjangoOpenAPIResponse(response)
|
||||||
|
result = validator.validate(openapi_request, openapi_response)
|
||||||
|
assert not result.errors
|
||||||
|
|
||||||
|
def test_request_validator_path_pattern(
|
||||||
|
self, django_spec, request_factory):
|
||||||
|
from django.urls import resolve
|
||||||
|
validator = RequestValidator(django_spec)
|
||||||
|
request = request_factory.get('/admin/auth/group/1/')
|
||||||
|
request.resolver_match = resolve('/admin/auth/group/1/')
|
||||||
|
openapi_request = DjangoOpenAPIRequest(request)
|
||||||
|
result = validator.validate(openapi_request)
|
||||||
|
assert not result.errors
|
19
tests/integration/data/v3.0/django_factory.yaml
Normal file
19
tests/integration/data/v3.0/django_factory.yaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
openapi: "3.0.0"
|
||||||
|
info:
|
||||||
|
title: Basic OpenAPI specification used with test_flask.TestFlaskOpenAPIIValidation
|
||||||
|
version: "0.1"
|
||||||
|
servers:
|
||||||
|
- url: 'http://testserver'
|
||||||
|
paths:
|
||||||
|
'/admin/auth/group/{object_id}/':
|
||||||
|
parameters:
|
||||||
|
- name: object_id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: the ID of the resource to retrieve
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
get:
|
||||||
|
responses:
|
||||||
|
default:
|
||||||
|
description: Return the resource.
|
Loading…
Reference in a new issue