Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch/fix doc urls in landing #673

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## [Unreleased]

## [2.5.5] - 2024-04-24

### Fixed

* Fix `service-doc` and `service-desc` url in landing page when using router prefix

## [2.5.4] - 2024-04-24

### Fixed
Expand Down
118 changes: 118 additions & 0 deletions stac_fastapi/api/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from datetime import datetime
from typing import List, Optional, Union

import pytest
from stac_pydantic import Collection, Item
from stac_pydantic.api.utils import link_factory

from stac_fastapi.types import core, stac
from stac_fastapi.types.core import NumType
from stac_fastapi.types.search import BaseSearchPostRequest

collection_links = link_factory.CollectionLinks("/", "test").create_links()
item_links = link_factory.ItemLinks("/", "test", "test").create_links()


@pytest.fixture
def _collection():
return Collection(
id="test_collection",
title="Test Collection",
description="A test collection",
keywords=["test"],
license="proprietary",
extent={
"spatial": {"bbox": [[-180, -90, 180, 90]]},
"temporal": {"interval": [["2000-01-01T00:00:00Z", None]]},
},
links=collection_links,
)


@pytest.fixture
def collection(_collection: Collection):
return _collection.json()


@pytest.fixture
def collection_dict(_collection: Collection):
return _collection.dict()


@pytest.fixture
def _item():
return Item(
id="test_item",
type="Feature",
geometry={"type": "Point", "coordinates": [0, 0]},
bbox=[-180, -90, 180, 90],
properties={"datetime": "2000-01-01T00:00:00Z"},
links=item_links,
assets={},
)


@pytest.fixture
def item(_item: Item):
return _item.json()


@pytest.fixture
def item_dict(_item: Item):
return _item.dict()


@pytest.fixture
def TestCoreClient(collection_dict, item_dict):
class CoreClient(core.BaseCoreClient):
def post_search(
self, search_request: BaseSearchPostRequest, **kwargs
) -> stac.ItemCollection:
return stac.ItemCollection(
type="FeatureCollection", features=[stac.Item(**item_dict)]
)

def get_search(
self,
collections: Optional[List[str]] = None,
ids: Optional[List[str]] = None,
bbox: Optional[List[NumType]] = None,
intersects: Optional[str] = None,
datetime: Optional[Union[str, datetime]] = None,
limit: Optional[int] = 10,
**kwargs,
) -> stac.ItemCollection:
return stac.ItemCollection(
type="FeatureCollection", features=[stac.Item(**item_dict)]
)

def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac.Item:
return stac.Item(**item_dict)

def all_collections(self, **kwargs) -> stac.Collections:
return stac.Collections(
collections=[stac.Collection(**collection_dict)],
links=[
{"href": "test", "rel": "root"},
{"href": "test", "rel": "self"},
{"href": "test", "rel": "parent"},
],
)

def get_collection(self, collection_id: str, **kwargs) -> stac.Collection:
return stac.Collection(**collection_dict)

def item_collection(
self,
collection_id: str,
bbox: Optional[List[Union[float, int]]] = None,
datetime: Optional[Union[str, datetime]] = None,
limit: int = 10,
token: str = None,
**kwargs,
) -> stac.ItemCollection:
return stac.ItemCollection(
type="FeatureCollection", features=[stac.Item(**item_dict)]
)

return CoreClient
66 changes: 66 additions & 0 deletions stac_fastapi/api/tests/test_app_prefix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import urllib
from typing import Optional

import pytest
from fastapi import APIRouter
from starlette.testclient import TestClient

from stac_fastapi.api.app import StacApi
from stac_fastapi.types.config import ApiSettings


def get_link(landing_page, rel_type, method: Optional[str] = None):
return next(
filter(
lambda link: link["rel"] == rel_type
and (not method or link.get("method") == method),
landing_page["links"],
),
None,
)


@pytest.mark.parametrize("prefix", ["", "/a_prefix"])
def test_api_prefix(TestCoreClient, prefix):
api_settings = ApiSettings(
openapi_url=f"{prefix}/api",
docs_url=f"{prefix}/api.html",
)

api = StacApi(
settings=api_settings,
client=TestCoreClient(),
router=APIRouter(prefix=prefix),
)

with TestClient(api.app, base_url="http://stac.io") as client:
landing = client.get(f"{prefix}/")
assert landing.status_code == 200, landing.json()

service_doc = client.get(f"{prefix}/api.html")
assert service_doc.status_code == 200, service_doc.text

service_desc = client.get(f"{prefix}/api")
assert service_desc.status_code == 200, service_desc.json()

conformance = client.get(f"{prefix}/conformance")
assert conformance.status_code == 200, conformance.json()

link_tests = [
("root", "application/json", "/"),
("conformance", "application/json", "/conformance"),
("service-doc", "text/html", "/api.html"),
("service-desc", "application/vnd.oai.openapi+json;version=3.0", "/api"),
]

for rel_type, expected_media_type, expected_path in link_tests:
link = get_link(landing.json(), rel_type)

assert link is not None, f"Missing {rel_type} link in landing page"
assert link.get("type") == expected_media_type

link_path = urllib.parse.urlsplit(link.get("href")).path
assert link_path == prefix + expected_path

resp = client.get(prefix + expected_path)
assert resp.status_code == 200
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 2 additions & 6 deletions stac_fastapi/types/stac_fastapi/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,9 +404,7 @@ def landing_page(self, **kwargs) -> stac_types.LandingPage:
"rel": "service-desc",
"type": "application/vnd.oai.openapi+json;version=3.0",
"title": "OpenAPI service description",
"href": urljoin(
str(request.base_url), request.app.openapi_url.lstrip("/")
),
"href": str(request.url_for("openapi")),
}
)

Expand All @@ -416,9 +414,7 @@ def landing_page(self, **kwargs) -> stac_types.LandingPage:
"rel": "service-doc",
"type": "text/html",
"title": "OpenAPI service documentation",
"href": urljoin(
str(request.base_url), request.app.docs_url.lstrip("/")
),
"href": str(request.url_for("swagger_ui_html")),
}
)

Expand Down