Skip to content

Commit 185b09c

Browse files
authored
Fix content-type of /api response (#287)
* Fix content-type of /api response * Add to changelog * Reduce footprint of openapi fix
1 parent cad5e5c commit 185b09c

File tree

5 files changed

+57
-2
lines changed

5 files changed

+57
-2
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
* The minimum `limit` value for searches is now 1 ([#296](https://github.com/stac-utils/stac-fastapi/pull/296))
1414
* Links stored with Collections and Items (e.g. license links) are now returned with those STAC objects ([#282](https://github.com/stac-utils/stac-fastapi/pull/282))
15+
* Content-type response headers for the /api endpoint now reflect those expected in the STAC api spec ([#287](https://github.com/stac-utils/stac-fastapi/pull/287))
1516

1617
## [2.2.0]
1718

stac_fastapi/api/stac_fastapi/api/app.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
SearchGetRequest,
2323
_create_request_model,
2424
)
25+
from stac_fastapi.api.openapi import update_openapi
2526
from stac_fastapi.api.routes import create_async_endpoint, create_sync_endpoint
2627

2728
# TODO: make this module not depend on `stac_fastapi.extensions`
@@ -64,8 +65,10 @@ class StacApi:
6465
)
6566
app: FastAPI = attr.ib(
6667
default=attr.Factory(
67-
lambda self: FastAPI(openapi_url=self.settings.openapi_url), takes_self=True
68-
)
68+
lambda self: FastAPI(openapi_url=self.settings.openapi_url),
69+
takes_self=True,
70+
),
71+
converter=update_openapi,
6972
)
7073
router: APIRouter = attr.ib(default=attr.Factory(APIRouter))
7174
title: str = attr.ib(default="stac-fastapi")

stac_fastapi/api/stac_fastapi/api/openapi.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
11
"""openapi."""
22
from fastapi import FastAPI
33
from fastapi.openapi.utils import get_openapi
4+
from starlette.requests import Request
5+
from starlette.responses import JSONResponse
46

57
from stac_fastapi.api.config import ApiExtensions
68
from stac_fastapi.types.config import ApiSettings
79

810

11+
class VndOaiResponse(JSONResponse):
12+
"""JSON with custom, vendor content-type."""
13+
14+
media_type = "application/vnd.oai.openapi+json;version=3.0"
15+
16+
17+
def update_openapi(app: FastAPI) -> FastAPI:
18+
"""Update OpenAPI response content-type.
19+
20+
This function modifies the openapi route to comply with the STAC API spec's
21+
required content-type response header
22+
"""
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)
37+
)
38+
# Add the updated openapi route
39+
app.add_route(app.openapi_url, openapi, include_in_schema=False)
40+
return app
41+
42+
943
# TODO: Remove or fix, this is currently unused
1044
# and calls a missing method on ApiSettings
1145
def config_openapi(app: FastAPI, settings: ApiSettings):

stac_fastapi/pgstac/tests/api/test_api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@
2323
]
2424

2525

26+
@pytest.mark.asyncio
27+
async def test_api_headers(app_client):
28+
resp = await app_client.get("/api")
29+
assert (
30+
resp.headers["content-type"] == "application/vnd.oai.openapi+json;version=3.0"
31+
)
32+
assert resp.status_code == 200
33+
34+
2635
@pytest.mark.asyncio
2736
async def test_core_router(api_client):
2837
core_routes = set(STAC_CORE_ROUTES)

stac_fastapi/sqlalchemy/tests/api/test_api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
]
2424

2525

26+
def test_api_headers(app_client):
27+
resp = app_client.get("/api")
28+
assert (
29+
resp.headers["content-type"] == "application/vnd.oai.openapi+json;version=3.0"
30+
)
31+
assert resp.status_code == 200
32+
33+
2634
def test_core_router(api_client):
2735
core_routes = set(STAC_CORE_ROUTES)
2836
api_routes = set(

0 commit comments

Comments
 (0)