Skip to content

Commit

Permalink
Fix content-type of /api response (#287)
Browse files Browse the repository at this point in the history
* Fix content-type of /api response

* Add to changelog

* Reduce footprint of openapi fix
  • Loading branch information
moradology authored Nov 30, 2021
1 parent cad5e5c commit 185b09c
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

* The minimum `limit` value for searches is now 1 ([#296](https://github.com/stac-utils/stac-fastapi/pull/296))
* 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))
* 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))

## [2.2.0]

Expand Down
7 changes: 5 additions & 2 deletions stac_fastapi/api/stac_fastapi/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
SearchGetRequest,
_create_request_model,
)
from stac_fastapi.api.openapi import update_openapi
from stac_fastapi.api.routes import create_async_endpoint, create_sync_endpoint

# TODO: make this module not depend on `stac_fastapi.extensions`
Expand Down Expand Up @@ -64,8 +65,10 @@ class StacApi:
)
app: FastAPI = attr.ib(
default=attr.Factory(
lambda self: FastAPI(openapi_url=self.settings.openapi_url), takes_self=True
)
lambda self: FastAPI(openapi_url=self.settings.openapi_url),
takes_self=True,
),
converter=update_openapi,
)
router: APIRouter = attr.ib(default=attr.Factory(APIRouter))
title: str = attr.ib(default="stac-fastapi")
Expand Down
34 changes: 34 additions & 0 deletions stac_fastapi/api/stac_fastapi/api/openapi.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
"""openapi."""
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from starlette.requests import Request
from starlette.responses import JSONResponse

from stac_fastapi.api.config import ApiExtensions
from stac_fastapi.types.config import ApiSettings


class VndOaiResponse(JSONResponse):
"""JSON with custom, vendor content-type."""

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


def update_openapi(app: FastAPI) -> FastAPI:
"""Update OpenAPI response content-type.
This function modifies the openapi route to comply with the STAC API spec's
required content-type response header
"""
urls = (server_data.get("url") for server_data in app.servers)
server_urls = {url for url in urls if url}

async def openapi(req: Request) -> JSONResponse:
root_path = req.scope.get("root_path", "").rstrip("/")
if root_path not in server_urls:
if root_path and app.root_path_in_servers:
app.servers.insert(0, {"url": root_path})
server_urls.add(root_path)
return VndOaiResponse(app.openapi())

# Remove the default openapi route
app.router.routes = list(
filter(lambda r: r.path != app.openapi_url, app.router.routes)
)
# Add the updated openapi route
app.add_route(app.openapi_url, openapi, include_in_schema=False)
return app


# TODO: Remove or fix, this is currently unused
# and calls a missing method on ApiSettings
def config_openapi(app: FastAPI, settings: ApiSettings):
Expand Down
9 changes: 9 additions & 0 deletions stac_fastapi/pgstac/tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
]


@pytest.mark.asyncio
async def test_api_headers(app_client):
resp = await app_client.get("/api")
assert (
resp.headers["content-type"] == "application/vnd.oai.openapi+json;version=3.0"
)
assert resp.status_code == 200


@pytest.mark.asyncio
async def test_core_router(api_client):
core_routes = set(STAC_CORE_ROUTES)
Expand Down
8 changes: 8 additions & 0 deletions stac_fastapi/sqlalchemy/tests/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
]


def test_api_headers(app_client):
resp = app_client.get("/api")
assert (
resp.headers["content-type"] == "application/vnd.oai.openapi+json;version=3.0"
)
assert resp.status_code == 200


def test_core_router(api_client):
core_routes = set(STAC_CORE_ROUTES)
api_routes = set(
Expand Down

0 comments on commit 185b09c

Please sign in to comment.