use prepared request to format payload before converting

This commit is contained in:
Elisha Yadgaran 2020-11-17 00:12:56 -08:00 committed by p1c2u
parent 6a222b93df
commit 5a91425c68

View file

@ -1,5 +1,8 @@
"""OpenAPI core contrib requests requests module""" """OpenAPI core contrib requests requests module"""
from typing import Union
from werkzeug.datastructures import ImmutableMultiDict from werkzeug.datastructures import ImmutableMultiDict
from requests import Request, PreparedRequest
from urllib.parse import urlparse, parse_qs
from openapi_core.validation.request.datatypes import ( from openapi_core.validation.request.datatypes import (
RequestParameters, OpenAPIRequest, RequestParameters, OpenAPIRequest,
@ -9,26 +12,57 @@ from openapi_core.validation.request.datatypes import (
class RequestsOpenAPIRequestFactory(object): class RequestsOpenAPIRequestFactory(object):
@classmethod @classmethod
def create(cls, request): def create(cls, request: Union[Request, PreparedRequest]) -> OpenAPIRequest:
"""
Converts a requests request to an OpenAPI one
Internally converts to a `PreparedRequest` first to parse the exact
payload being sent
"""
if isinstance(request, Request):
request = request.prepare()
# Method
method = request.method.lower() method = request.method.lower()
cookie = request.cookies or {} # Cookies
if request._cookies is not None:
# cookies are stored in a cookiejar object
cookie = request._cookies.get_dict()
else:
cookie = {}
# Preparing a request formats the URL with params, strip them out again
o = urlparse(request.url)
params = parse_qs(o.query)
# extract the URL without query parameters
url = o._replace(query=None).geturl()
# gets deduced by path finder against spec # gets deduced by path finder against spec
path = {} path = {}
mimetype = request.headers.get('Accept') or \ # Order matters because all python requests issued from a session include
request.headers.get('Content-Type') # Accept */* which does not necessarily match the content type
mimetype = request.headers.get('Content-Type') or \
request.headers.get('Accept')
# Headers - request.headers is not an instance of dict, which is expected
header = dict(request.headers)
# Body
# TODO: figure out if request._body_position is relevant
body = request.body
parameters = RequestParameters( parameters = RequestParameters(
query=ImmutableMultiDict(request.params), query=ImmutableMultiDict(params),
header=request.headers, header=header,
cookie=cookie, cookie=cookie,
path=path, path=path,
) )
return OpenAPIRequest( return OpenAPIRequest(
full_url_pattern=request.url, full_url_pattern=url,
method=method, method=method,
parameters=parameters, parameters=parameters,
body=request.data, body=body,
mimetype=mimetype, mimetype=mimetype,
) )