Skip to content

Commit 94f6e2c

Browse files
eseglemgadomski
andauthored
Rework update_openapi function. (#523)
* Rework update_openapi function. * Update changelog. * Additional documentation and add removed code back as deprecated. * chore: fixup changelog * refactor: move VndOaiResponse back to old location --------- Co-authored-by: Pete Gadomski <pete.gadomski@gmail.com>
1 parent 90e158d commit 94f6e2c

File tree

3 files changed

+54
-20
lines changed

3 files changed

+54
-20
lines changed

Diff for: CHANGES.md

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
### Changed
1111

1212
* Updated CI to test against [pgstac v0.6.12](https://github.com/stac-utils/pgstac/releases/tag/v0.6.12) ([#511](https://github.com/stac-utils/stac-fastapi/pull/511))
13+
* Reworked `update_openapi` and added a test for it ([#523](https://github.com/stac-utils/stac-fastapi/pull/523))
1314

1415
### Removed
1516

@@ -24,6 +25,10 @@
2425
* Manually exclude non-truthy optional values from sqlalchemy serialization of Collections ([#508](https://github.com/stac-utils/stac-fastapi/pull/508))
2526
* Deleting items that had repeated ids in other collections ([#520](https://github.com/stac-utils/stac-fastapi/pull/520))
2627

28+
### Deprecated
29+
30+
* Deprecated `VndOaiResponse` and `config_openapi`, will be removed in v3.0 ([#523](https://github.com/stac-utils/stac-fastapi/pull/523))
31+
2732
## [2.4.3] - 2022-11-25
2833

2934
### Added

Diff for: stac_fastapi/api/stac_fastapi/api/openapi.py

+40-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
"""openapi."""
2+
import warnings
3+
24
from fastapi import FastAPI
35
from fastapi.openapi.utils import get_openapi
46
from starlette.requests import Request
5-
from starlette.responses import JSONResponse
7+
from starlette.responses import JSONResponse, Response
8+
from starlette.routing import Route, request_response
69

710
from stac_fastapi.api.config import ApiExtensions
811
from stac_fastapi.types.config import ApiSettings
@@ -13,37 +16,54 @@ class VndOaiResponse(JSONResponse):
1316

1417
media_type = "application/vnd.oai.openapi+json;version=3.0"
1518

19+
def __init__(self, *args, **kwargs):
20+
"""Init function with deprecation warning."""
21+
warnings.warn(
22+
"VndOaiResponse is deprecated and will be removed in v3.0",
23+
DeprecationWarning,
24+
)
25+
super().__init__(*args, **kwargs)
26+
1627

1728
def update_openapi(app: FastAPI) -> FastAPI:
1829
"""Update OpenAPI response content-type.
1930
2031
This function modifies the openapi route to comply with the STAC API spec's
21-
required content-type response header
32+
required content-type response header.
2233
"""
23-
urls = (server_data.get("url") for server_data in app.servers)
24-
server_urls = {url for url in urls if url}
25-
26-
async def openapi(req: Request) -> JSONResponse:
27-
root_path = req.scope.get("root_path", "").rstrip("/")
28-
if root_path not in server_urls:
29-
if root_path and app.root_path_in_servers:
30-
app.servers.insert(0, {"url": root_path})
31-
server_urls.add(root_path)
32-
return VndOaiResponse(app.openapi())
33-
34-
# Remove the default openapi route
35-
app.router.routes = list(
36-
filter(lambda r: r.path != app.openapi_url, app.router.routes)
34+
# Find the route for the openapi_url in the app
35+
openapi_route: Route = next(
36+
route for route in app.router.routes if route.path == app.openapi_url
3737
)
38-
# Add the updated openapi route
39-
app.add_route(app.openapi_url, openapi, include_in_schema=False)
38+
# Store the old endpoint function so we can call it from the patched function
39+
old_endpoint = openapi_route.endpoint
40+
41+
# Create a patched endpoint function that modifies the content type of the response
42+
async def patched_openapi_endpoint(req: Request) -> Response:
43+
# Get the response from the old endpoint function
44+
response: JSONResponse = await old_endpoint(req)
45+
# Update the content type header in place
46+
response.headers[
47+
"content-type"
48+
] = "application/vnd.oai.openapi+json;version=3.0"
49+
# Return the updated response
50+
return response
51+
52+
# When a Route is accessed the `handle` function calls `self.app`. Which is
53+
# the endpoint function wrapped with `request_response`. So we need to wrap
54+
# our patched function and replace the existing app with it.
55+
openapi_route.app = request_response(patched_openapi_endpoint)
56+
57+
# return the patched app
4058
return app
4159

4260

43-
# TODO: Remove or fix, this is currently unused
44-
# and calls a missing method on ApiSettings
4561
def config_openapi(app: FastAPI, settings: ApiSettings):
4662
"""Config openapi."""
63+
warnings.warn(
64+
"config_openapi is deprecated and will be removed in v3.0",
65+
DeprecationWarning,
66+
)
4767

4868
def custom_openapi():
4969
"""Config openapi."""

Diff for: stac_fastapi/api/tests/test_api.py

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ def _assert_dependency_applied(api, routes):
4949
), "Authenticated requests should be accepted"
5050
assert response.json() == "dummy response"
5151

52+
def test_openapi_content_type(self):
53+
api = self._build_api()
54+
with TestClient(api.app) as client:
55+
response = client.get(api.settings.openapi_url)
56+
assert (
57+
response.headers["content-type"]
58+
== "application/vnd.oai.openapi+json;version=3.0"
59+
)
60+
5261
def test_build_api_with_route_dependencies(self):
5362
routes = [
5463
{"path": "/collections", "method": "POST"},

0 commit comments

Comments
 (0)