mirror of
https://github.com/correl/openapi-core.git
synced 2024-11-22 03:00:10 +00:00
Merge pull request #185 from p1c2u/feature/flask-openapi-request-parameters
Flask OpenAPI request parameters
This commit is contained in:
commit
09bff35e3a
5 changed files with 69 additions and 35 deletions
15
README.rst
15
README.rst
|
@ -218,6 +218,21 @@ As an alternative to the decorator-based integration, Flask method based views c
|
|||
|
||||
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
|
||||
=========
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@ class FlaskOpenAPIViewDecorator(OpenAPIDecorator):
|
|||
request_provider, openapi_errors_handler,
|
||||
)
|
||||
|
||||
def _handle_request_view(self, request_result, view, *args, **kwargs):
|
||||
request = self._get_request(*args, **kwargs)
|
||||
request.openapi = request_result
|
||||
return super(FlaskOpenAPIViewDecorator, self)._handle_request_view(
|
||||
request_result, view, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_spec(
|
||||
cls,
|
||||
|
|
|
@ -27,22 +27,30 @@ class OpenAPIDecorator(OpenAPIProcessor):
|
|||
def decorated(*args, **kwargs):
|
||||
request = self._get_request(*args, **kwargs)
|
||||
openapi_request = self._get_openapi_request(request)
|
||||
errors = self.process_request(openapi_request)
|
||||
if errors:
|
||||
return self._handle_openapi_errors(errors)
|
||||
response = view(*args, **kwargs)
|
||||
request_result = self.process_request(openapi_request)
|
||||
if request_result.errors:
|
||||
return self._handle_request_errors(request_result)
|
||||
response = self._handle_request_view(
|
||||
request_result, view, *args, **kwargs)
|
||||
openapi_response = self._get_openapi_response(response)
|
||||
errors = self.process_response(openapi_request, openapi_response)
|
||||
if errors:
|
||||
return self._handle_openapi_errors(errors)
|
||||
response_result = self.process_response(
|
||||
openapi_request, openapi_response)
|
||||
if response_result.errors:
|
||||
return self._handle_response_errors(response_result)
|
||||
return response
|
||||
return decorated
|
||||
|
||||
def _get_request(self, *args, **kwargs):
|
||||
return self.request_provider.provide(*args, **kwargs)
|
||||
|
||||
def _handle_openapi_errors(self, errors):
|
||||
return self.openapi_errors_handler.handle(errors)
|
||||
def _handle_request_view(self, request_result, view, *args, **kwargs):
|
||||
return view(*args, **kwargs)
|
||||
|
||||
def _handle_request_errors(self, request_result):
|
||||
return self.openapi_errors_handler.handle(request_result.errors)
|
||||
|
||||
def _handle_response_errors(self, response_result):
|
||||
return self.openapi_errors_handler.handle(response_result.errors)
|
||||
|
||||
def _get_openapi_request(self, request):
|
||||
return self.request_factory.create(request)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
"""OpenAPI core validation processors module"""
|
||||
from openapi_core.schema.servers.exceptions import InvalidServer
|
||||
from openapi_core.schema.exceptions import OpenAPIMappingError
|
||||
|
||||
|
||||
class OpenAPIProcessor(object):
|
||||
|
@ -10,22 +8,7 @@ class OpenAPIProcessor(object):
|
|||
self.response_validator = response_validator
|
||||
|
||||
def process_request(self, request):
|
||||
request_result = self.request_validator.validate(request)
|
||||
try:
|
||||
request_result.raise_for_errors()
|
||||
# return instantly on server error
|
||||
except InvalidServer as exc:
|
||||
return [exc, ]
|
||||
except OpenAPIMappingError:
|
||||
return request_result.errors
|
||||
else:
|
||||
return
|
||||
return self.request_validator.validate(request)
|
||||
|
||||
def process_response(self, request, response):
|
||||
response_result = self.response_validator.validate(request, response)
|
||||
try:
|
||||
response_result.raise_for_errors()
|
||||
except OpenAPIMappingError:
|
||||
return response_result.errors
|
||||
else:
|
||||
return
|
||||
return self.response_validator.validate(request, response)
|
||||
|
|
|
@ -3,11 +3,12 @@ import pytest
|
|||
|
||||
from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
|
||||
from openapi_core.shortcuts import create_spec
|
||||
from openapi_core.validation.request.datatypes import RequestParameters
|
||||
|
||||
|
||||
class TestFlaskOpenAPIDecorator(object):
|
||||
|
||||
view_response = None
|
||||
view_response_callable = None
|
||||
|
||||
@pytest.fixture
|
||||
def spec(self, factory):
|
||||
|
@ -31,17 +32,30 @@ class TestFlaskOpenAPIDecorator(object):
|
|||
with app.app_context():
|
||||
yield client
|
||||
|
||||
@pytest.fixture
|
||||
def view_response(self):
|
||||
def view_response(*args, **kwargs):
|
||||
return self.view_response_callable(*args, **kwargs)
|
||||
return view_response
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def view(self, app, decorator):
|
||||
def view(self, app, decorator, view_response):
|
||||
@app.route("/browse/<id>/")
|
||||
@decorator
|
||||
def browse_details(id):
|
||||
return self.view_response
|
||||
def browse_details(*args, **kwargs):
|
||||
return view_response(*args, **kwargs)
|
||||
return browse_details
|
||||
|
||||
def test_invalid_content_type(self, client):
|
||||
self.view_response = make_response('success', 200)
|
||||
|
||||
def view_response_callable(*args, **kwargs):
|
||||
from flask.globals import request
|
||||
assert request.openapi
|
||||
assert not request.openapi.errors
|
||||
assert request.openapi.parameters == RequestParameters(path={
|
||||
'id': 12,
|
||||
})
|
||||
return make_response('success', 200)
|
||||
self.view_response_callable = view_response_callable
|
||||
result = client.get('/browse/12/')
|
||||
|
||||
assert result.json == {
|
||||
|
@ -101,7 +115,15 @@ class TestFlaskOpenAPIDecorator(object):
|
|||
assert result.json == expected_data
|
||||
|
||||
def test_valid(self, client):
|
||||
self.view_response = jsonify(data='data')
|
||||
def view_response_callable(*args, **kwargs):
|
||||
from flask.globals import request
|
||||
assert request.openapi
|
||||
assert not request.openapi.errors
|
||||
assert request.openapi.parameters == RequestParameters(path={
|
||||
'id': 12,
|
||||
})
|
||||
return jsonify(data='data')
|
||||
self.view_response_callable = view_response_callable
|
||||
|
||||
result = client.get('/browse/12/')
|
||||
|
||||
|
|
Loading…
Reference in a new issue