Skip to content

Commit b5aabf2

Browse files
committed
FlaskOpenAPIView handler change
1 parent 0f7fa52 commit b5aabf2

File tree

2 files changed

+120
-23
lines changed

2 files changed

+120
-23
lines changed

openapi_core/contrib/flask/views.py

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,26 @@
22
from flask.views import MethodView
33

44
from openapi_core.contrib.flask.decorators import FlaskOpenAPIViewDecorator
5+
from openapi_core.contrib.flask.handlers import FlaskOpenAPIErrorsHandler
56
from openapi_core.validation.request.validators import RequestValidator
67
from openapi_core.validation.response.validators import ResponseValidator
78

89

910
class FlaskOpenAPIView(MethodView):
1011
"""Brings OpenAPI specification validation and unmarshalling for views."""
1112

12-
def __init__(self, request_validator, response_validator):
13-
super(MethodView, self).__init__()
14-
self.request_validator = request_validator
15-
self.response_validator = response_validator
13+
openapi_errors_handler = FlaskOpenAPIErrorsHandler
14+
15+
def __init__(self, spec):
16+
super(FlaskOpenAPIView, self).__init__()
17+
self.request_validator = RequestValidator(spec)
18+
self.response_validator = ResponseValidator(spec)
1619

1720
def dispatch_request(self, *args, **kwargs):
1821
decorator = FlaskOpenAPIViewDecorator(
1922
request_validator=self.request_validator,
2023
response_validator=self.response_validator,
21-
openapi_errors_handler=self.handle_openapi_errors,
24+
openapi_errors_handler=self.openapi_errors_handler,
2225
)
2326
return decorator(super(FlaskOpenAPIView, self).dispatch_request)(
2427
*args, **kwargs)
25-
26-
def handle_openapi_errors(self, errors):
27-
"""Handles OpenAPI request/response errors.
28-
29-
Should return response object::
30-
31-
class MyView(FlaskOpenAPIView):
32-
33-
def handle_openapi_errors(self, errors):
34-
return jsonify({'errors': errors})
35-
"""
36-
raise NotImplementedError
37-
38-
@classmethod
39-
def from_spec(cls, spec):
40-
request_validator = RequestValidator(spec)
41-
response_validator = ResponseValidator(spec)
42-
return cls(request_validator, response_validator)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from flask import Flask, make_response, jsonify
2+
import pytest
3+
4+
from openapi_core.contrib.flask.views import FlaskOpenAPIView
5+
from openapi_core.shortcuts import create_spec
6+
7+
8+
class TestFlaskOpenAPIView(object):
9+
10+
view_response = None
11+
12+
@pytest.fixture
13+
def spec(self, factory):
14+
specfile = 'contrib/flask/data/v3.0/flask_factory.yaml'
15+
return create_spec(factory.spec_from_file(specfile))
16+
17+
@pytest.fixture
18+
def app(self):
19+
app = Flask("__main__")
20+
app.config['DEBUG'] = True
21+
app.config['TESTING'] = True
22+
return app
23+
24+
@pytest.yield_fixture
25+
def client(self, app):
26+
with app.test_client() as client:
27+
with app.app_context():
28+
yield client
29+
30+
@pytest.fixture
31+
def view_func(self, spec):
32+
outer = self
33+
34+
class MyView(FlaskOpenAPIView):
35+
def get(self, id):
36+
return outer.view_response
37+
return MyView.as_view('browse_details', spec)
38+
39+
@pytest.fixture(autouse=True)
40+
def view(self, app, view_func):
41+
app.add_url_rule("/browse/<id>/", view_func=view_func)
42+
43+
def test_invalid_content_type(self, client):
44+
self.view_response = make_response('success', 200)
45+
46+
result = client.get('/browse/12/')
47+
48+
assert result.json == {
49+
'errors': [
50+
{
51+
'class': (
52+
"<class 'openapi_core.schema.media_types.exceptions."
53+
"InvalidContentType'>"
54+
),
55+
'status': 415,
56+
'title': (
57+
'Content for following mimetype not found: text/html'
58+
)
59+
}
60+
]
61+
}
62+
63+
def test_server_error(self, client):
64+
result = client.get('/browse/12/', base_url='https://localhost')
65+
66+
expected_data = {
67+
'errors': [
68+
{
69+
'class': (
70+
"<class 'openapi_core.schema.servers.exceptions."
71+
"InvalidServer'>"
72+
),
73+
'status': 500,
74+
'title': (
75+
'Invalid request server '
76+
'https://localhost/browse/{id}/'
77+
),
78+
}
79+
]
80+
}
81+
assert result.json == expected_data
82+
83+
def test_endpoint_error(self, client):
84+
result = client.get('/browse/invalidparameter/')
85+
86+
expected_data = {
87+
'errors': [
88+
{
89+
'class': (
90+
"<class 'openapi_core.schema.parameters."
91+
"exceptions.InvalidParameterValue'>"
92+
),
93+
'status': 400,
94+
'title': (
95+
'Invalid parameter value for `id`: '
96+
'Failed to cast value invalidparameter to type '
97+
'SchemaType.INTEGER'
98+
)
99+
}
100+
]
101+
}
102+
assert result.json == expected_data
103+
104+
def test_valid(self, client):
105+
self.view_response = jsonify(data='data')
106+
107+
result = client.get('/browse/12/')
108+
109+
assert result.status_code == 200
110+
assert result.json == {
111+
'data': 'data',
112+
}

0 commit comments

Comments
 (0)