Skip to content

Commit 832bf8d

Browse files
committed
Starlette skip validating response
1 parent ae4ac91 commit 832bf8d

File tree

5 files changed

+102
-12
lines changed

5 files changed

+102
-12
lines changed

openapi_core/contrib/starlette/middlewares.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""OpenAPI core contrib starlette middlewares module"""
22

3+
from typing import Type
4+
35
from starlette.middleware.base import BaseHTTPMiddleware
46
from starlette.middleware.base import RequestResponseEndpoint
57
from starlette.requests import Request
@@ -14,14 +16,26 @@
1416
StarletteOpenAPIValidRequestHandler,
1517
)
1618
from openapi_core.contrib.starlette.integrations import StarletteIntegration
19+
from openapi_core.contrib.starlette.requests import StarletteOpenAPIRequest
20+
from openapi_core.contrib.starlette.responses import StarletteOpenAPIResponse
1721

1822

1923
class StarletteOpenAPIMiddleware(StarletteIntegration, BaseHTTPMiddleware):
2024
valid_request_handler_cls = StarletteOpenAPIValidRequestHandler
2125
errors_handler = StarletteOpenAPIErrorsHandler()
2226

23-
def __init__(self, app: ASGIApp, openapi: OpenAPI):
27+
def __init__(
28+
self,
29+
app: ASGIApp,
30+
openapi: OpenAPI,
31+
request_cls: Type[StarletteOpenAPIRequest] = StarletteOpenAPIRequest,
32+
response_cls: Type[
33+
StarletteOpenAPIResponse
34+
] = StarletteOpenAPIResponse,
35+
):
2436
super().__init__(openapi)
37+
self.request_cls = request_cls
38+
self.response_cls = response_cls
2539
BaseHTTPMiddleware.__init__(self, app)
2640

2741
async def dispatch(

tests/integration/contrib/starlette/data/v3.0/starletteproject/__main__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from starletteproject.pets.endpoints import pet_detail_endpoint
66
from starletteproject.pets.endpoints import pet_list_endpoint
77
from starletteproject.pets.endpoints import pet_photo_endpoint
8+
from starletteproject.tags.endpoints import tag_list_endpoint
89

910
from openapi_core.contrib.starlette.middlewares import (
1011
StarletteOpenAPIMiddleware,
@@ -16,17 +17,30 @@
1617
openapi=openapi,
1718
),
1819
]
20+
middleware_skip_response = [
21+
Middleware(
22+
StarletteOpenAPIMiddleware,
23+
openapi=openapi,
24+
response_cls=None,
25+
),
26+
]
1927

2028
routes = [
2129
Route("/v1/pets", pet_list_endpoint, methods=["GET", "POST"]),
2230
Route("/v1/pets/{petId}", pet_detail_endpoint, methods=["GET", "POST"]),
2331
Route(
2432
"/v1/pets/{petId}/photo", pet_photo_endpoint, methods=["GET", "POST"]
2533
),
34+
Route("/v1/tags", tag_list_endpoint, methods=["GET"]),
2635
]
2736

2837
app = Starlette(
2938
debug=True,
3039
middleware=middleware,
3140
routes=routes,
3241
)
42+
app_skip_response = Starlette(
43+
debug=True,
44+
middleware=middleware_skip_response,
45+
routes=routes,
46+
)

tests/integration/contrib/starlette/data/v3.0/starletteproject/tags/__init__.py

Whitespace-only changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from starlette.responses import Response
2+
3+
4+
async def tag_list_endpoint(request):
5+
assert request.scope["openapi"]
6+
assert not request.scope["openapi"].errors
7+
assert request.method == "GET"
8+
headers = {
9+
"X-Rate-Limit": "12",
10+
}
11+
return Response(status_code=201, headers=headers)

tests/integration/contrib/starlette/test_starlette_project.py

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,18 @@ def project_setup():
1515
sys.path.remove(project_dir)
1616

1717

18-
@pytest.fixture
19-
def app():
20-
from starletteproject.__main__ import app
21-
22-
return app
23-
18+
class BaseTestPetstore:
19+
api_key = "12345"
2420

25-
@pytest.fixture
26-
def client(app):
27-
return TestClient(app, base_url="http://petstore.swagger.io")
21+
@pytest.fixture
22+
def app(self):
23+
from starletteproject.__main__ import app
2824

25+
return app
2926

30-
class BaseTestPetstore:
31-
api_key = "12345"
27+
@pytest.fixture
28+
def client(self, app):
29+
return TestClient(app, base_url="http://petstore.swagger.io")
3230

3331
@property
3432
def api_key_encoded(self):
@@ -37,6 +35,19 @@ def api_key_encoded(self):
3735
return str(api_key_bytes_enc, "utf8")
3836

3937

38+
class BaseTestPetstoreSkipReponse:
39+
40+
@pytest.fixture
41+
def app(self):
42+
from starletteproject.__main__ import app_skip_response
43+
44+
return app_skip_response
45+
46+
@pytest.fixture
47+
def client(self, app):
48+
return TestClient(app, base_url="http://petstore.swagger.io")
49+
50+
4051
class TestPetListEndpoint(BaseTestPetstore):
4152
def test_get_no_required_param(self, client):
4253
headers = {
@@ -381,3 +392,43 @@ def test_post_valid(self, client, data_gif):
381392

382393
assert not response.text
383394
assert response.status_code == 201
395+
396+
397+
class TestTagListEndpoint(BaseTestPetstore):
398+
399+
def test_get_invalid(self, client):
400+
headers = {
401+
"Authorization": "Basic testuser",
402+
}
403+
404+
response = client.get(
405+
"/v1/tags",
406+
headers=headers,
407+
)
408+
409+
assert response.status_code == 400
410+
assert response.json() == {
411+
"errors": [
412+
{
413+
"title": "Missing response data",
414+
"status": 400,
415+
"type": "<class 'openapi_core.validation.response.exceptions.MissingData'>",
416+
},
417+
],
418+
}
419+
420+
421+
class TestSkipResponseTagListEndpoint(BaseTestPetstoreSkipReponse):
422+
423+
def test_get_valid(self, client):
424+
headers = {
425+
"Authorization": "Basic testuser",
426+
}
427+
428+
response = client.get(
429+
"/v1/tags",
430+
headers=headers,
431+
)
432+
433+
assert not response.text
434+
assert response.status_code == 201

0 commit comments

Comments
 (0)