STAC FastAPI extension for multi-tenant catalogs
Project description
Jump to: | Table of Contents |
stac-fastapi multi-tenant virtual catalogs extension
STAC FastAPI extension for multi-tenant, recursive catalog hierarchies.
This package adds a dedicated /catalogs registry and scoped catalog routes so a single STAC API deployment can serve multiple logical catalog trees. It is designed for use cases where one API needs tenant-style isolation, curated views, provider-specific trees, or thematic navigation across shared datasets.
The extension supports poly-hierarchy (multi-parenting), where a collection or catalog can be linked under multiple catalog paths without duplicating data. It also supports contextual navigation for scoped routes, preserving UI breadcrumb behavior while still exposing alternative parents through related links.
Implementation status
| Project | Status | Notes |
|---|---|---|
| stac-fastapi-elasticsearch-opensearch (SFEOS) | Implemented | Active integration target for this extension |
| stac-fastapi-pgstac | Implemented | Active integration target for this extension |
| stac-fastapi-mongo | Not implemented yet | Planned |
Last verified: 2026-03-22
Table of contents
- Implementation status
- Specification reference
- Conformance class guidance
- What this package provides
- Supported projects
- Install
- Integrate in a STAC FastAPI deployment
- Backend client requirements
- Notes for common deployment repos
- Endpoints added by this extension
Specification reference
This implementation is aligned with the Multi-Tenant Catalogs extension work in StacLabs:
Notable concepts adopted here include:
- Recursive /catalogs endpoint structure
- Optional transaction management plane
- Safety-first unlink semantics (organizational operations are non-destructive)
- Runtime link generation for parent/child/related relationships
Conformance class guidance
When enabling this extension in your deployment, advertise conformance classes according to your enabled capabilities:
- Required:
- Recommended:
- Optional (only if transaction endpoints are enabled):
- Optional (only if scoped search endpoints are enabled):
Operational guidance:
- Read-only/public APIs should not expose POST/PUT/DELETE catalog endpoints and should not advertise the transaction conformance class.
- If transactions are enabled, expose and document the management endpoints and include the transaction conformance class in conformance responses.
- Important: To preserve the poly-hierarchy DAG structure, updates to
collections SHOULD be performed through scoped routes
(
/catalogs/{catalogId}/collections/{collectionId}) rather than the core STAC route (/collections/{collectionId}). The core route is flat and does not maintain parent-child relationships, so updates through that route may not properly preserve the hierarchical context.
Multi-Tenant Security
For multi-tenant deployments where you want to prevent information leakage about
other tenants, use the hide_alternate_parents flag:
CatalogsExtension(
client=catalogs_client,
hide_alternate_parents=True, # Disables rel="related" links to alternative parents
)
When hide_alternate_parents=True, the API will only advertise the single
contextual parent through rel="parent" and will not expose alternative parents
via rel="related" links. This prevents clients from discovering the names and
structure of other tenants in the system.
Supported projects
This extension is designed for STAC FastAPI deployment applications and is currently supported in:
- SFEOS: https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
- stac-fastapi-pgstac: https://github.com/stac-utils/stac-fastapi-pgstac
Planned (not yet implemented):
- stac-fastapi-mongo: https://github.com/stac-utils/stac-fastapi-mongo
It can also be integrated into custom STAC FastAPI deployments that implement the AsyncBaseCatalogsClient contract.
What this package provides
- Three STAC FastAPI extension classes:
CatalogsExtension: Read-only discovery endpoints for catalogsCatalogsTransactionExtension: Write operations (POST, PUT, DELETE) for catalog managementCatalogsSearchExtension: Scoped search endpoints bounded to a catalog's descendant tree
- Request/response models for catalogs, children, and search APIs
- Abstract client contracts:
AsyncBaseCatalogsClientandAsyncCatalogsSearchClient
This package wires routes and validation into your API. Your deployment app is responsible for providing a concrete client implementation backed by your database/search stack.
Install
pip install stac-fastapi-catalogs-extension
Integrate in a STAC FastAPI deployment
In your deployment app.py (for example in
stac-fastapi-elasticsearch-opensearch), instantiate StacApi with
CatalogsExtension and optionally CatalogsTransactionExtension and/or
CatalogsSearchExtension, passing an implementation of AsyncBaseCatalogsClient.
Read-only deployment (discovery only)
from stac_fastapi.api.app import StacApi
from stac_fastapi.types.config import ApiSettings
from stac_fastapi_catalogs_extension import (
CatalogsExtension,
CATALOGS_CORE_CONFORMANCE,
)
from my_project.catalogs_client import CatalogsClient
from my_project.core_client import CoreClient
settings = ApiSettings()
core_client = CoreClient(...)
catalogs_client = CatalogsClient(...)
api = StacApi(
settings=settings,
client=core_client,
extensions=[
CatalogsExtension(
client=catalogs_client,
conformance_classes=list(CATALOGS_CORE_CONFORMANCE),
settings=settings.model_dump(),
)
],
)
app = api.app
With transaction support (read and write)
from stac_fastapi.api.app import StacApi
from stac_fastapi.types.config import ApiSettings
from stac_fastapi_catalogs_extension import (
CatalogsExtension,
CatalogsTransactionExtension,
)
from my_project.catalogs_client import CatalogsClient
from my_project.core_client import CoreClient
settings = ApiSettings()
core_client = CoreClient(...)
catalogs_client = CatalogsClient(...)
api = StacApi(
settings=settings,
client=core_client,
extensions=[
CatalogsExtension(
client=catalogs_client,
settings=settings.model_dump(),
),
CatalogsTransactionExtension(
client=catalogs_client,
settings=settings.model_dump(),
),
],
)
app = api.app
The transaction conformance class is automatically registered when
CatalogsTransactionExtension is included.
With scoped search support
from stac_fastapi.api.app import StacApi
from stac_fastapi.types.config import ApiSettings
from stac_fastapi.types.search import BaseSearchGetRequest, BaseSearchPostRequest
from stac_fastapi_catalogs_extension import (
CatalogsExtension,
CatalogsSearchExtension,
CATALOGS_SEARCH_CONFORMANCE,
)
from my_project.catalogs_client import CatalogsClient
from my_project.core_client import CoreClient
settings = ApiSettings()
core_client = CoreClient(...)
catalogs_client = CatalogsClient(...)
# In a real deployment, these models are generated dynamically by
# your search extensions (e.g., FilterExtension, SortExtension).
# We pass them to CatalogsSearchExtension so scoped searches inherit them!
get_request_model = BaseSearchGetRequest
post_request_model = BaseSearchPostRequest
api = StacApi(
settings=settings,
client=core_client,
extensions=[
CatalogsExtension(
client=catalogs_client,
settings=settings.model_dump(),
),
CatalogsSearchExtension(
client=catalogs_client,
search_get_request_model=get_request_model,
search_post_request_model=post_request_model,
conformance_classes=list(CATALOGS_SEARCH_CONFORMANCE),
settings=settings.model_dump(),
),
],
)
app = api.app
The search conformance classes are automatically registered when
CatalogsSearchExtension is included. This enables scoped search via:
GET /catalogs/{catalog_id}/search- Query parameter-based searchPOST /catalogs/{catalog_id}/search- JSON body-based search
Both endpoints perform recursive tree traversal to search only items in collections linked to the specified catalog and its descendants.
Key architectural benefit: By injecting the dynamic core search request models,
the scoped search endpoints automatically inherit any features added to the global
/search endpoint (CQL2 filtering, sorting, field projection, etc.), ensuring
scoped searches are always feature-complete!
Inheriting Core Search Extensions (Filter, Sort, Fields)
If your core STAC API utilizes extensions that modify the global /search endpoint
(such as the FilterExtension for CQL2, SortExtension, or FieldsExtension),
the scoped search endpoints can automatically inherit these exact same capabilities.
By passing the dynamically generated request models from your core API setup into
the CatalogsSearchExtension, you guarantee that multi-tenant users have access
to the same advanced querying features inside their sub-catalogs:
# Generate models using your core stac-fastapi extensions
get_request_model = create_get_request_model(core_extensions)
post_request_model = create_post_request_model(core_extensions)
CatalogsSearchExtension(
search_get_request_model=get_request_model,
search_post_request_model=post_request_model,
# ...
)
This makes it crystal clear that the scoped search isn't a "second-class citizen" endpoint—it is functionally identical to the main search!
Backend client requirements
Your CatalogsClient should subclass AsyncBaseCatalogsClient and implement the required async methods, including:
- get_catalogs
- get_catalog
- create_catalog
- update_catalog
- delete_catalog
- get_catalog_collections
- create_catalog_collection
- get_catalog_collection
- update_catalog_collection
- unlink_catalog_collection
- get_catalog_collection_items
- get_catalog_collection_item
- get_sub_catalogs
- create_sub_catalog
- unlink_sub_catalog
- get_catalog_children
- get_catalog_conformance
- get_catalog_queryables
If you are supporting Scoped Search, your client must also subclass
AsyncCatalogsSearchClient and implement:
get_all_descendant_collectionscatalog_search_getcatalog_search_post
Notes for common deployment repos
stac-fastapi-elasticsearch-opensearch style deployment
- Build a catalogs client that reads/writes catalog links and hierarchy metadata from your OpenSearch/Elasticsearch index strategy.
- Reuse your existing core client for global /collections and /search routes.
- Add CatalogsExtension to the extensions list in app.py as shown above.
stac-fastapi-pgstac style deployment
- Build a catalogs client that maps these methods to SQL functions or pgstac tables/views that represent catalog hierarchy and scoped membership.
- Keep link generation contextual for scoped routes (/catalogs/{id}/collections/{collection_id}) so UI breadcrumb navigation stays correct.
- Add CatalogsExtension to the extensions list in app.py as shown above.
Endpoints added by this extension
CatalogsExtension (read-only discovery)
- GET /catalogs
- GET /catalogs/{catalog_id}
- GET /catalogs/{catalog_id}/collections
- GET /catalogs/{catalog_id}/collections/{collection_id}
- GET /catalogs/{catalog_id}/collections/{collection_id}/items
- GET /catalogs/{catalog_id}/collections/{collection_id}/items/{item_id}
- GET /catalogs/{catalog_id}/catalogs
- GET /catalogs/{catalog_id}/children
- GET /catalogs/{catalog_id}/conformance
- GET /catalogs/{catalog_id}/queryables
CatalogsTransactionExtension (write operations)
When CatalogsTransactionExtension is enabled, the following additional endpoints are available for catalog and collection management:
- POST /catalogs
- PUT /catalogs/{catalog_id}
- DELETE /catalogs/{catalog_id}
- POST /catalogs/{catalog_id}/collections
- PUT /catalogs/{catalog_id}/collections/{collection_id}
- DELETE /catalogs/{catalog_id}/collections/{collection_id}
- POST /catalogs/{catalog_id}/catalogs
- DELETE /catalogs/{catalog_id}/catalogs/{sub_catalog_id}
CatalogsSearchExtension (scoped search)
When CatalogsSearchExtension is enabled, the following additional endpoints are available for searching items within a catalog's descendant tree:
- GET /catalogs/{catalog_id}/search
- POST /catalogs/{catalog_id}/search
These endpoints perform recursive tree traversal to search only items in
collections linked to the specified catalog and its descendants. They automatically
inherit any features from the global /search endpoint (CQL2 filtering, sorting,
field projection, etc.).
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stac_fastapi_catalogs_extension-0.5.0.tar.gz.
File metadata
- Download URL: stac_fastapi_catalogs_extension-0.5.0.tar.gz
- Upload date:
- Size: 22.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
893c6539eb484c91571befd95a722ba071ad55f04a4b81e69727fb3c3aacfffb
|
|
| MD5 |
04a687cc37667d7ad2323f0555c42cf7
|
|
| BLAKE2b-256 |
d9d780320a228201e8f6c0c9678644652d5ff861aa7a714c88c72455a2ba39fe
|
File details
Details for the file stac_fastapi_catalogs_extension-0.5.0-py3-none-any.whl.
File metadata
- Download URL: stac_fastapi_catalogs_extension-0.5.0-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35dbf9fdb26325d51f03927a93e8278d7079db43ac76d35f4280fd94269582d9
|
|
| MD5 |
0c76976a36e0d823efd2249d1f26c828
|
|
| BLAKE2b-256 |
5bdc7948cb8fdcf13ee1496c1e1b37d6fefe9e0b2fd288bdcf964240336a1723
|