From 28a3b232103d7f8577748df9f6547a64df2e9e91 Mon Sep 17 00:00:00 2001 From: Guillermo Tesoro Calvo Date: Tue, 28 Oct 2025 09:21:43 +0100 Subject: [PATCH 1/2] ORDERABLE self links now work properly --- stac_fastapi/eodag/core.py | 52 +++++++++++++++++++++++++++++- stac_fastapi/eodag/models/links.py | 18 ++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/stac_fastapi/eodag/core.py b/stac_fastapi/eodag/core.py index 618802d6..82aacd8b 100644 --- a/stac_fastapi/eodag/core.py +++ b/stac_fastapi/eodag/core.py @@ -19,6 +19,7 @@ from __future__ import annotations +import ast import asyncio import logging from typing import TYPE_CHECKING, Any, cast @@ -515,10 +516,59 @@ async def get_item(self, item_id: str, collection_id: str, request: Request, **k :returns: The item. :raises NotFoundError: If the item does not exist. """ + # If collection does not exist, NotFoundError wil be raised await self.get_collection(collection_id, request=request) - search_request = self.post_request_model(ids=[item_id], collections=[collection_id], limit=1) + # Handle query params set up for _ORDERABLE_ items + if "_ORDERABLE_" in item_id: + bbox: Optional[list[NumType]] = request.query_params.getlist("bbox") + datetime: Optional[str] = request.query_params.getlist("datetime") + query: Optional[dict[str, Any]] = request.query_params.getlist("query") + intersects: Optional[str] = request.query_params.getlist("intersects") + filter_expr: Optional[str] = request.query_params.getlist("filter_expr") + filter_lang: Optional[str] = request.query_params.getlist("filter_lang") + + bbox = bbox[0] if bbox else bbox + datetime = datetime[0] if datetime else datetime + query = ast.literal_eval(query[0]) if query else query + intersects = intersects[0] if intersects else intersects + filter_expr = ast.literal_eval(filter_expr[0]) if filter_expr else filter_expr + filter_lang = filter_lang[0] if filter_lang else "cql2-text" + + base_args = { + "collections": [collection_id], + "ids": [item_id], + "bbox": bbox, + "limit": 1, + "query": query, + "intersects": intersects, + } + + if datetime: + base_args["datetime"] = format_datetime_range(datetime) + + if filter_expr: + if filter_lang == "cql2-text": + filter_expr = to_cql2(parse_cql2_text(filter_expr)) + filter_lang = "cql2-json" + + base_args["filter"] = str2json("filter_expr", filter_expr) + base_args["filter_lang"] = "cql2-json" + + # Remove None values from dict + clean = {} + for k, v in base_args.items(): + if v is not None and v != []: + clean[k] = v + + try: + search_request = self.post_request_model(**clean) + except ValidationError as err: + raise HTTPException(status_code=400, detail=f"Invalid parameters provided {err}") from err + else: + search_request = self.post_request_model(ids=[item_id], collections=[collection_id], limit=1) + item_collection = self._search_base(search_request, request) if not item_collection["features"]: raise NotFoundError(f"Item {item_id} in Collection {collection_id} does not exist.") diff --git a/stac_fastapi/eodag/models/links.py b/stac_fastapi/eodag/models/links.py index edd2e3d7..a91b24c8 100644 --- a/stac_fastapi/eodag/models/links.py +++ b/stac_fastapi/eodag/models/links.py @@ -332,10 +332,26 @@ class ItemLinks(CollectionLinksBase): def link_self(self) -> dict[str, str]: """Create the self link.""" + + _href = self.resolve(f"collections/{self.collection_id}/items/{self.item_id}") + + # Orderable items need to contain their search parameters on the self link + # to be able to return them later on. + if "_ORDERABLE_" in self.item_id: + _params = "" + # POST search + if hasattr(self.request, "_json"): + _params = urlencode(self.request._json) + else: + # GET search + _params = str(self.request.query_params) + + _href = f"{_href}?{_params}" + return { "rel": Relations.self.value, "type": MimeTypes.geojson.value, - "href": self.resolve(f"collections/{self.collection_id}/items/{self.item_id}"), + "href": _href, "title": "Original item link", } From b565233eb28dcfa2269c5480c1fe075cd9951be5 Mon Sep 17 00:00:00 2001 From: Guillermo Tesoro Calvo Date: Tue, 28 Oct 2025 09:34:47 +0100 Subject: [PATCH 2/2] Typing issues fixed --- stac_fastapi/eodag/core.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stac_fastapi/eodag/core.py b/stac_fastapi/eodag/core.py index 82aacd8b..3420ff0a 100644 --- a/stac_fastapi/eodag/core.py +++ b/stac_fastapi/eodag/core.py @@ -522,19 +522,19 @@ async def get_item(self, item_id: str, collection_id: str, request: Request, **k # Handle query params set up for _ORDERABLE_ items if "_ORDERABLE_" in item_id: - bbox: Optional[list[NumType]] = request.query_params.getlist("bbox") - datetime: Optional[str] = request.query_params.getlist("datetime") - query: Optional[dict[str, Any]] = request.query_params.getlist("query") - intersects: Optional[str] = request.query_params.getlist("intersects") - filter_expr: Optional[str] = request.query_params.getlist("filter_expr") - filter_lang: Optional[str] = request.query_params.getlist("filter_lang") - - bbox = bbox[0] if bbox else bbox - datetime = datetime[0] if datetime else datetime - query = ast.literal_eval(query[0]) if query else query - intersects = intersects[0] if intersects else intersects - filter_expr = ast.literal_eval(filter_expr[0]) if filter_expr else filter_expr - filter_lang = filter_lang[0] if filter_lang else "cql2-text" + _bbox = request.query_params.getlist("bbox") + _datetime = request.query_params.getlist("datetime") + _query = request.query_params.getlist("query") + _intersects = request.query_params.getlist("intersects") + _filter_expr = request.query_params.getlist("filter_expr") + _filter_lang = request.query_params.getlist("filter_lang") + + bbox = _bbox[0] if _bbox else None + datetime = _datetime[0] if _datetime else None + query = ast.literal_eval(_query[0]) if _query else None + intersects = _intersects[0] if _intersects else None + filter_expr = ast.literal_eval(_filter_expr[0]) if _filter_expr else None + filter_lang = _filter_lang[0] if _filter_lang else "cql2-text" base_args = { "collections": [collection_id],