geopython / geopython/pygeoapi
STAC: Make `/search` compliant with Item-Search spec
- Dominant language
- Python
- Stars
- 624
- Forks
- 326
- Avg merge
- 8h 25m
- Merged PRs (30d)
- 2
Description
**Note:** This Issue is subject to RFC4: https://pygeoapi.io/development/rfc/4
## Is your feature request related to a problem? Please describe.
Per the [STAC API spec](https://github.com/radiantearth/stac-api-spec/blob/release/v1.0.0/overview.md#endpoints), `/search` is Item Search: it returns an `ItemCollection` of STAC Items, and its filters (`bbox`, `datetime`, `ids`, `collections`, `intersects`) select Items across one or more collections.
Producing STAC Items has two parts. #2355 established that the backend-specific part — reading `collection`, `assets`, and `links` out of whatever shape a store keeps them in, and placing them at the top level of a Feature — [belongs in a provider, not in `stac.py`](https://github.com/geopython/pygeoapi/issues/2355#issuecomment). This issue covers the backend-agnostic part: converting a shape-correct Feature into a conformant Item Search response in core.
Today [`pygeoapi.api.stac.search`](https://github.com/geopython/pygeoapi/blob/b5844a03ada922c3268b1c9160b4027212ac8bf1/pygeoapi/api/stac.py#L293-L301) unions the features of each `type: stac-collection` resource by flipping the resource `type` to `collection` and calling `itemtypes.get_collection_items` ([L359-L363](https://github.com/geopython/pygeoapi/blob/b5844a03ada922c3268b1c9160b4027212ac8bf1/pygeoapi/api/stac.py#L359-L363)), then post-processing each feature ([L372-L386](https://github.com/geopython/pygeoapi/blob/b5844a03ada922c3268b1c9160b4027212ac8bf1/pygeoapi/api/stac.py#L372-L386)). Two required pieces are not produced, and neither can come from a provider because both derive from the request rather than from stored data:
1. **Per-Item links are not generated.** A STAC Item requires `self`, `parent`, `collection`, and `root` links, built from the pygeoapi base URL plus the collection id and item id. `search()` adds only response-level `root`/`prev`/`next` links; each feature's `links` is defaulted to `[]` ([L382-L383](https://github.com/geopython/pygeoapi/blob/b5844a03ada922c3268b1c9160b4027212ac8bf1/pygeoapi/api/stac.py#L382-L383)).
2. **The response is not declared or framed as Item Search.** No STAC API Item Search conformance class is advertised, and the code frames results as collections (the docstring reads "STAC API Queries stac-collection"; results are collected into a `collections` variable).
Because `/search` is not explicitly Item Search, the `collections` filter proposed in #2372 has no correct target: it selects Items by parent collection, which only has meaning once results are Items that carry a `collection`.
## Describe the solution you'd like
Handle Item Search in core, operating on shape-correct Features supplied by a provider:
- Generate the `self`, `parent`, `collection`, and `root` links for each Item from the request context.
- Advertise the STAC API Item Search conformance class in the STAC landing page `conformsTo`.
- Update the naming and docstring of `pygeoapi.api.stac.search` to reflect Item Search.
This follows how OGC API Records is implemented: backend-agnostic profiling and conformance live in the API layer (`itemtypes.get_collection_items` branches on `feature` vs `record` at [L336-L342](https://github.com/geopython/pygeoapi/blob/b5844a03ada922c3268b1c9160b4027212ac8bf1/pygeoapi/api/itemtypes.py#L336-L342) and declares Records conformance classes), while backend-specific shaping lives in providers. STAC Item Search follows the same split: `stac.py` for the agnostic conversion and links, a provider for backend shaping.
## Describe alternatives you've considered
- **Perform the backend shaping in `stac.py`** (for example, relocating `collection`/`assets`/`links` out of `feature.properties`). Rejected in #2355 because the source shape is backend-specific and `stac.py` should stay backend-agnostic. Excluded here.
- **Leave `/search` unchanged and correct results client-side.** Non-conformant; per-Item links cannot be reconstructed by a client, and `/search` is defined as Item Search.
- **Model one `stac-collection` resource per STAC collection.** Fits pygeoapi's one-resource-per-collection model, but does not scale to catalogs holding many collections' items in a single store. Item Search over a shared, multi-collection store, filtered by `collections`, is the target use case.
## Additional context
Part of a sequence of STAC API changes for the USGS NHGF work (continuation of #2129, #2153, #2340):
- This issue — core Item Search: per-Item links, conformance, and naming.
- (separate, forthcoming) — a STAC provider that supplies shape-correct Features from a SQL store (the backend half of #2355).
- #2372 — add `ids` and `collections` filters to `/search` (depends on this issue).
- (separate, forthcoming) — a Collection Search endpoint at `/collections`.
- (separate, forthcoming) — rename the `stac-collection` resource `type`, which becomes ambiguous once Collection Search exists, with a back-compatible alias.
Contributor guide
Research direction
Start in pygeoapi/api/stac.py at search(), using the linked lines to trace current result framing and per-feature link handling; review itemtypes.py for the existing API-layer conformance pattern. Update Item Search naming, request-derived per-Item links, and the STAC landing page conformance declaration, then verify that /search returns conformant Item Search responses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100