Skip to content

Commit cacd67d

Browse files
committed
Starlette skip validating response
1 parent ae4ac91 commit cacd67d

File tree

5 files changed

+99
-12
lines changed

5 files changed

+99
-12
lines changed

openapi_core/contrib/starlette/middlewares.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""OpenAPI core contrib starlette middlewares module"""
2+
from typing import Type
23

34
from starlette.middleware.base import BaseHTTPMiddleware
45
from starlette.middleware.base import RequestResponseEndpoint
@@ -14,14 +15,24 @@
1415
StarletteOpenAPIValidRequestHandler,
1516
)
1617
from openapi_core.contrib.starlette.integrations import StarletteIntegration
18+
from openapi_core.contrib.starlette.requests import StarletteOpenAPIRequest
19+
from openapi_core.contrib.starlette.responses import StarletteOpenAPIResponse
1720

1821

1922
class StarletteOpenAPIMiddleware(StarletteIntegration, BaseHTTPMiddleware):
2023
valid_request_handler_cls = StarletteOpenAPIValidRequestHandler
2124
errors_handler = StarletteOpenAPIErrorsHandler()
2225

23-
def __init__(self, app: ASGIApp, openapi: OpenAPI):
26+
def __init__(
27+
self,
28+
app: ASGIApp,
29+
openapi: OpenAPI,
30+
request_cls: Type[StarletteOpenAPIRequest] = StarletteOpenAPIRequest,
31+
response_cls: Type[StarletteOpenAPIResponse] = StarletteOpenAPIResponse,
32+
):
2433
super().__init__(openapi)
34+
self.request_cls = request_cls
35+
self.response_cls = response_cls
2536
BaseHTTPMiddleware.__init__(self, app)
2637

2738
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)