Repository: stac-utils/stac-fastapi
Pull request #795 (2025-01-30 15:32:29)

Release/v5.0.1
`SearchFilterExtension` is an alias to `FilterExtension` which is specific to the global queryable endpoint (`/queryables`) so we need to check both `FilterExtension` and `SearchFilterExtension` in order to add the link in the landing page

Added other tests for the Aggregation extensions as well 


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index e083005..91f88d3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,12 @@
 
 ## [Unreleased]
 
+## [5.0.1] - 2025-01-30
+
+### Fixed
+
+- add `Queryables` links when `SearchFilterExtension` is enabled
+
 ## [5.0.0] - 2025-01-30
 
 ### Changed
@@ -563,7 +569,8 @@ Full changelog: https://stac-utils.github.io/stac-fastapi/migrations/v3.0.0/#cha
 
 * First PyPi release!
 
-[Unreleased]: <https://github.com/stac-utils/stac-fastapi/compare/5.0.0..main>
+[Unreleased]: <https://github.com/stac-utils/stac-fastapi/compare/5.0.1..main>
+[5.0.1]: <https://github.com/stac-utils/stac-fastapi/compare/5.0.0..5.0.1>
 [5.0.0]: <https://github.com/stac-utils/stac-fastapi/compare/4.0.1..5.0.0>
 [4.0.1]: <https://github.com/stac-utils/stac-fastapi/compare/4.0.0..4.0.1>
 [4.0.0]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.5..4.0.0>
diff --git a/VERSION b/VERSION
index 0062ac9..6b244dc 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-5.0.0
+5.0.1
diff --git a/pyproject.toml b/pyproject.toml
index e49b638..b566922 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ section-order = ["future", "standard-library", "third-party", "first-party", "lo
 quote-style = "double"
 
 [tool.bumpversion]
-current_version = "5.0.0"
+current_version = "5.0.1"
 parse = """(?x)
     (?P<major>\\d+)\\.
     (?P<minor>\\d+)\\.
diff --git a/stac_fastapi/api/stac_fastapi/api/version.py b/stac_fastapi/api/stac_fastapi/api/version.py
index d13d0b9..b49655b 100644
--- a/stac_fastapi/api/stac_fastapi/api/version.py
+++ b/stac_fastapi/api/stac_fastapi/api/version.py
@@ -1,3 +1,3 @@
 """Library version."""
 
-__version__ = "5.0.0"
+__version__ = "5.0.1"
diff --git a/stac_fastapi/extensions/stac_fastapi/extensions/version.py b/stac_fastapi/extensions/stac_fastapi/extensions/version.py
index d13d0b9..b49655b 100644
--- a/stac_fastapi/extensions/stac_fastapi/extensions/version.py
+++ b/stac_fastapi/extensions/stac_fastapi/extensions/version.py
@@ -1,3 +1,3 @@
 """Library version."""
 
-__version__ = "5.0.0"
+__version__ = "5.0.1"
diff --git a/stac_fastapi/types/stac_fastapi/types/core.py b/stac_fastapi/types/stac_fastapi/types/core.py
index 1885b82..e4ad4d2 100644
--- a/stac_fastapi/types/stac_fastapi/types/core.py
+++ b/stac_fastapi/types/stac_fastapi/types/core.py
@@ -384,7 +384,9 @@ class BaseCoreClient(LandingPageMixin, abc.ABC):
         )
 
         # Add Queryables link
-        if self.extension_is_enabled("FilterExtension"):
+        if self.extension_is_enabled("FilterExtension") or self.extension_is_enabled(
+            "SearchFilterExtension"
+        ):
             landing_page["links"].append(
                 {
                     "rel": Relations.queryables.value,
@@ -605,7 +607,9 @@ class AsyncBaseCoreClient(LandingPageMixin, abc.ABC):
         )
 
         # Add Queryables link
-        if self.extension_is_enabled("FilterExtension"):
+        if self.extension_is_enabled("FilterExtension") or self.extension_is_enabled(
+            "SearchFilterExtension"
+        ):
             landing_page["links"].append(
                 {
                     "rel": Relations.queryables.value,
diff --git a/stac_fastapi/types/stac_fastapi/types/version.py b/stac_fastapi/types/stac_fastapi/types/version.py
index d13d0b9..b49655b 100644
--- a/stac_fastapi/types/stac_fastapi/types/version.py
+++ b/stac_fastapi/types/stac_fastapi/types/version.py
@@ -1,3 +1,3 @@
 """Library version."""
 
-__version__ = "5.0.0"
+__version__ = "5.0.1"


Test patch:
diff --git a/stac_fastapi/api/tests/test_app.py b/stac_fastapi/api/tests/test_app.py
index 59b09d9..417d12f 100644
--- a/stac_fastapi/api/tests/test_app.py
+++ b/stac_fastapi/api/tests/test_app.py
@@ -15,7 +15,11 @@ from stac_fastapi.api.models import (
     create_get_request_model,
     create_post_request_model,
 )
-from stac_fastapi.extensions.core import FieldsExtension, FilterExtension
+from stac_fastapi.extensions.core import (
+    FieldsExtension,
+    FilterExtension,
+    SearchFilterExtension,
+)
 from stac_fastapi.types import stac
 from stac_fastapi.types.config import ApiSettings
 from stac_fastapi.types.core import BaseCoreClient, NumType
@@ -184,6 +188,40 @@ def test_filter_extension(validate, TestCoreClient, item_dict):
         )
 
     assert landing.status_code == 200, landing.text
+    assert "Queryables" in [link.get("title") for link in landing.json()["links"]]
+    assert get_search.status_code == 200, get_search.text
+    assert post_search.status_code == 200, post_search.text
+
+    test_app = app.StacApi(
+        settings=ApiSettings(enable_response_models=validate),
+        client=FilterClient(),
+        search_get_request_model=create_get_request_model([SearchFilterExtension()]),
+        search_post_request_model=create_post_request_model([SearchFilterExtension()]),
+        extensions=[SearchFilterExtension()],
+    )
+
+    with TestClient(test_app.app) as client:
+        landing = client.get("/")
+        get_search = client.get(
+            "/search",
+            params={
+                "filter": "TEST",
+                "filter-crs": "EPSG:4326",
+                "filter-lang": "cql2-text",
+            },
+        )
+        post_search = client.post(
+            "/search",
+            json={
+                "collections": ["test"],
+                "filter": {},
+                "filter-crs": "EPSG:4326",
+                "filter-lang": "cql2-json",
+            },
+        )
+
+    assert landing.status_code == 200, landing.text
+    assert "Queryables" in [link.get("title") for link in landing.json()["links"]]
     assert get_search.status_code == 200, get_search.text
     assert post_search.status_code == 200, post_search.text
 
diff --git a/stac_fastapi/extensions/tests/test_aggregation.py b/stac_fastapi/extensions/tests/test_aggregation.py
index 480cc66..fca45a7 100644
--- a/stac_fastapi/extensions/tests/test_aggregation.py
+++ b/stac_fastapi/extensions/tests/test_aggregation.py
@@ -20,7 +20,7 @@ from stac_fastapi.types.core import BaseCoreClient
 
 class DummyCoreClient(BaseCoreClient):
     def all_collections(self, *args, **kwargs):
-        raise NotImplementedError
+        return {"collections": [], "links": []}
 
     def get_collection(self, *args, **kwargs):
         raise NotImplementedError
@@ -38,48 +38,6 @@ class DummyCoreClient(BaseCoreClient):
         raise NotImplementedError
 
 
-def test_get_aggregations(client: TestClient) -> None:
-    response = client.get("/aggregations")
-    assert response.is_success, response.text
-    assert response.json()["aggregations"] == [
-        {"name": "total_count", "data_type": "integer"}
-    ]
-    assert AggregationCollection(
-        type="AggregationCollection",
-        aggregations=[Aggregation(**response.json()["aggregations"][0])],
-    )
-
-
-def test_get_aggregate(client: TestClient) -> None:
-    response = client.get("/aggregate")
-    assert response.is_success, response.text
-    assert response.json()["aggregations"] == []
-    assert AggregationCollection(
-        type="AggregationCollection", aggregations=response.json()["aggregations"]
-    )
-
-
-def test_post_aggregations(client: TestClient) -> None:
-    response = client.post("/aggregations")
-    assert response.is_success, response.text
-    assert response.json()["aggregations"] == [
-        {"name": "total_count", "data_type": "integer"}
-    ]
-    assert AggregationCollection(
-        type="AggregationCollection",
-        aggregations=[Aggregation(**response.json()["aggregations"][0])],
-    )
-
-
-def test_post_aggregate(client: TestClient) -> None:
-    response = client.post("/aggregate", content="{}")
-    assert response.is_success, response.text
-    assert response.json()["aggregations"] == []
-    assert AggregationCollection(
-        type="AggregationCollection", aggregations=response.json()["aggregations"]
-    )
-
-
 @pytest.fixture
 def client(
     core_client: DummyCoreClient, aggregations_client: BaseAggregationClient
@@ -132,3 +90,40 @@ def test_agg_get_query():
         params = response.json()
         assert params["collections"] == ["collection1", "collection2"]
         assert params["aggregations"] == ["prop1", "prop2"]
+
+
+def test_landing(client: TestClient) -> None:
+    landing = client.get("/")
+    assert landing.status_code == 200, landing.text
+    assert "Aggregate" in [link.get("title") for link in landing.json()["links"]]
+    assert "Aggregations" in [link.get("title") for link in landing.json()["links"]]
+
+
+def test_get_aggregate(client: TestClient) -> None:
+    response = client.get("/aggregate")
+    assert response.is_success, response.text
+    assert response.json()["aggregations"] == []
+    assert AggregationCollection(
+        type="AggregationCollection", aggregations=response.json()["aggregations"]
+    )
+
+
+def test_post_aggregations(client: TestClient) -> None:
+    response = client.post("/aggregations")
+    assert response.is_success, response.text
+    assert response.json()["aggregations"] == [
+        {"name": "total_count", "data_type": "integer"}
+    ]
+    assert AggregationCollection(
+        type="AggregationCollection",
+        aggregations=[Aggregation(**response.json()["aggregations"][0])],
+    )
+
+
+def test_post_aggregate(client: TestClient) -> None:
+    response = client.post("/aggregate", content="{}")
+    assert response.is_success, response.text
+    assert response.json()["aggregations"] == []
+    assert AggregationCollection(
+        type="AggregationCollection", aggregations=response.json()["aggregations"]
+    )