From d055d89e284c0ef683b638d24f7ee37b70740406 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Tue, 9 Dec 2025 16:27:55 -0500 Subject: [PATCH 1/4] Fix STAC search endpoint reference This mistakenly used double slashes in the URL which would break the output. A single slash fixes this. Closes https://github.com/geopython/pygeoapi/issues/2354 --- pygeoapi/api/stac.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygeoapi/api/stac.py b/pygeoapi/api/stac.py index ebf86b6e8..f86bba2ac 100644 --- a/pygeoapi/api/stac.py +++ b/pygeoapi/api/stac.py @@ -284,7 +284,7 @@ def landing_page(api: API, 'rel': 'search', 'type': FORMAT_TYPES[F_JSON], 'title': l10n.translate('STAC API search', request.locale), - 'href': f"{api.base_url}/stac-api//search?f={F_JSON}" + 'href': f"{api.base_url}/stac-api/search?f={F_JSON}" }] return headers, status, to_json(content, api.pretty_print) From 1ad933d6d274ee78a327fc2304074eeedfa842a4 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Tue, 9 Dec 2025 16:55:21 -0500 Subject: [PATCH 2/4] Assets should be dict, not list As specified in the STAC spec: https://stacspec.org/en/about/stac-spec/ assets are dicts, not lists. When missing, now they are initialized as the correct empty data structures. Closes https://github.com/geopython/pygeoapi/issues/2354 --- pygeoapi/api/stac.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pygeoapi/api/stac.py b/pygeoapi/api/stac.py index f86bba2ac..a2a63c8ee 100644 --- a/pygeoapi/api/stac.py +++ b/pygeoapi/api/stac.py @@ -379,9 +379,11 @@ def search(api: API, request: Union[APIRequest, Any]) -> Tuple[dict, int, str]: geom = from_geojson(json.dumps(feature['geometry'])) feature['bbox'] = geom.bounds - for la in ['links', 'assets']: - if feature.get(la) is None: - feature[la] = [] + if feature.get('links') is None: + feature['links'] = [] + + if feature.get('assets') is None: + feature['assets'] = {} stac_api_response['numberReturned'] = len(stac_api_response['features']) From d3c61438579fabd4720e0b9d7feeb31f7dede9e5 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Tue, 9 Dec 2025 17:14:23 -0500 Subject: [PATCH 3/4] Correctly source links, assets from pgSTAC Althought the STAC specification expects links and assets to be top-level items, this is not the case in pgSTAC tables, which store the details in a `contents` JSONB column: https://github.com/stac-utils/pgstac/blob/08ce5991e7840f51993d508c715fad44f889e5e5/src/pgstac/pgstac.sql#L889-L899 In cases where the top-level items are not available, we attempt to source them fromm the pgSTAC-specific source if available. Closes https://github.com/geopython/pygeoapi/issues/2355 --- pygeoapi/api/stac.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pygeoapi/api/stac.py b/pygeoapi/api/stac.py index a2a63c8ee..4e3cba3f0 100644 --- a/pygeoapi/api/stac.py +++ b/pygeoapi/api/stac.py @@ -380,10 +380,16 @@ def search(api: API, request: Union[APIRequest, Any]) -> Tuple[dict, int, str]: feature['bbox'] = geom.bounds if feature.get('links') is None: - feature['links'] = [] + feature['links'] = feature\ + .get('properties', {})\ + .get('content', {})\ + .get('links', []) if feature.get('assets') is None: - feature['assets'] = {} + feature['assets'] = feature\ + .get('properties', {})\ + .get('content', {})\ + .get('assets', {}) stac_api_response['numberReturned'] = len(stac_api_response['features']) From 72e7a7f49285e2d6573c98b2bf4135e648c211f1 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Tue, 16 Dec 2025 16:22:30 -0500 Subject: [PATCH 4/4] Correctly initialize temporal instant Previously the `datetime` field was not used to initalize the temporal instant, causing it to be overridden by other approximations. This ensure that the initialization happens correctly, and the overrides only occur in cases when `datetime` is None. Closes https://github.com/geopython/pygeoapi/issues/2356 --- pygeoapi/api/stac.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pygeoapi/api/stac.py b/pygeoapi/api/stac.py index 4e3cba3f0..816e0a7a4 100644 --- a/pygeoapi/api/stac.py +++ b/pygeoapi/api/stac.py @@ -496,18 +496,20 @@ def get_temporal(feature: dict) -> dict: if datetime_ is None and None not in [start_datetime, end_datetime]: LOGGER.debug('Temporal range partially exists') elif datetime_ is not None: + value['datetime'] = datetime_ LOGGER.debug('Temporal instant exists') LOGGER.debug('Attempting to derive temporal from GeoJSON feature') LOGGER.debug(feature) - if feature.get('time') is not None: + if value.get('datetime') is None and feature.get('time') is not None: if feature['time'].get('timestamp') is not None: value['datetime'] = feature['time']['timestamp'] if feature['time'].get('interval') is not None: value['start_datetime'] = feature['time']['interval'][0] value['end_datetime'] = feature['time']['interval'][1] - if feature['properties'].get('created') is not None: + if value.get('datetime') is None \ + and feature['properties'].get('created') is not None: value['datetime'] = feature['properties']['created'] if not value: