Skip to content

Commit 2000b12

Browse files
committed
Django OpenAPI request/response factories
1 parent 0d62c5f commit 2000b12

File tree

10 files changed

+305
-105
lines changed

10 files changed

+305
-105
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from openapi_core.contrib.django.requests import DjangoOpenAPIRequestFactory
2+
from openapi_core.contrib.django.responses import DjangoOpenAPIResponseFactory
3+
4+
# backward compatibility
5+
DjangoOpenAPIRequest = DjangoOpenAPIRequestFactory.create
6+
DjangoOpenAPIResponse = DjangoOpenAPIResponseFactory.create
7+
8+
__all__ = [
9+
'DjangoOpenAPIRequestFactory', 'DjangoOpenAPIResponseFactory',
10+
'DjangoOpenAPIRequest', 'DjangoOpenAPIResponse',
11+
]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""OpenAPI core contrib django requests module"""
2+
import re
3+
4+
from openapi_core.validation.request.datatypes import (
5+
RequestParameters, OpenAPIRequest,
6+
)
7+
8+
# https://docs.djangoproject.com/en/2.2/topics/http/urls/
9+
#
10+
# Currently unsupported are :
11+
# - nested arguments, e.g.: ^comments/(?:page-(?P<page_number>\d+)/)?$
12+
# - unnamed regex groups, e.g.: ^articles/([0-9]{4})/$
13+
# - multiple named parameters between a single pair of slashes
14+
# e.g.: <page_slug>-<page_id>/edit/
15+
#
16+
# The regex matches everything, except a "/" until "<". Than only the name
17+
# is exported, after which it matches ">" and everything until a "/".
18+
PATH_PARAMETER_PATTERN = r'(?:[^\/]*?)<(?:(?:.*?:))*?(\w+)>(?:[^\/]*)'
19+
20+
21+
class DjangoOpenAPIRequestFactory(object):
22+
23+
path_regex = re.compile(PATH_PARAMETER_PATTERN)
24+
25+
@classmethod
26+
def create(cls, request):
27+
method = request.method.lower()
28+
29+
if request.resolver_match is None:
30+
path_pattern = request.path
31+
else:
32+
route = cls.path_regex.sub(
33+
r'{\1}', request.resolver_match.route)
34+
path_pattern = '/' + route
35+
36+
path = request.resolver_match and request.resolver_match.kwargs or {}
37+
parameters = RequestParameters(
38+
path=path,
39+
query=request.GET,
40+
header=request.headers,
41+
cookie=request.COOKIES,
42+
)
43+
return OpenAPIRequest(
44+
host_url=request._current_scheme_host,
45+
path=request.path,
46+
method=method,
47+
path_pattern=path_pattern,
48+
parameters=parameters,
49+
body=request.body,
50+
mimetype=request.content_type,
51+
)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""OpenAPI core contrib django responses module"""
2+
from openapi_core.validation.response.datatypes import OpenAPIResponse
3+
4+
5+
class DjangoOpenAPIResponseFactory(object):
6+
7+
@classmethod
8+
def create(cls, response):
9+
mimetype = response["Content-Type"]
10+
return OpenAPIResponse(
11+
data=response.content,
12+
status_code=response.status_code,
13+
mimetype=mimetype,
14+
)

openapi_core/validation/request/datatypes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@ def __getitem__(self, location):
2121

2222
@attr.s
2323
class OpenAPIRequest(object):
24+
"""OpenAPI request dataclass.
25+
26+
Attributes:
27+
path
28+
Requested path as string.
29+
path_pattern
30+
The matched url pattern.
31+
parameters
32+
A RequestParameters object.
33+
body
34+
The request body, as string.
35+
mimetype
36+
Like content type, but without parameters (eg, without charset,
37+
type etc.) and always lowercase.
38+
For example if the content type is "text/HTML; charset=utf-8"
39+
the mimetype would be "text/html".
40+
"""
2441

2542
host_url = attr.ib()
2643
path = attr.ib()

openapi_core/validation/response/datatypes.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66

77
@attr.s
88
class OpenAPIResponse(object):
9+
"""OpenAPI request dataclass.
10+
11+
Attributes:
12+
data
13+
The response body, as string.
14+
status_code
15+
The status code as integer.
16+
mimetype
17+
Lowercase content type without charset.
18+
"""
919

1020
data = attr.ib()
1121
status_code = attr.ib()

openapi_core/wrappers/django.py

Lines changed: 0 additions & 104 deletions
This file was deleted.

requirements_dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ mock==2.0.0
22
pytest==3.5.0
33
pytest-flake8
44
pytest-cov==2.5.1
5-
flask
5+
flask
6+
django==2.2.6

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ exclude =
4343
tests
4444

4545
[options.extras_require]
46+
django = django
4647
flask = werkzeug
4748

4849
[tool:pytest]

0 commit comments

Comments
 (0)