Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
6570957
route extension, create, get catalogs
jonhealy1 Mar 25, 2026
e05c740
>= python 3.12
jonhealy1 Mar 25, 2026
ad1ccb6
Merge branch 'main' into stac-fastapi-catalogs-extension
jonhealy1 Mar 26, 2026
0964ec0
Merge branch 'main' into stac-fastapi-catalogs-extension
jonhealy1 Apr 10, 2026
ee18b97
update to catalogs extension v0.1.3
jonhealy1 Apr 10, 2026
f127857
Merge branch 'stac-fastapi-catalogs-extension' of https://github.com/…
jonhealy1 Apr 10, 2026
19a166a
lint
jonhealy1 Apr 10, 2026
366cf7d
add to dev deps
jonhealy1 Apr 10, 2026
7e43b20
change class name
jonhealy1 Apr 11, 2026
1e3409b
sub-catalog scratch
jonhealy1 Apr 11, 2026
6487974
advertise ports
jonhealy1 Apr 11, 2026
8fc5d83
sub-catalog links, tests
jonhealy1 Apr 11, 2026
7237f29
lint
jonhealy1 Apr 11, 2026
e8b4503
ensure parent_ids list not returned
jonhealy1 Apr 11, 2026
080e3fe
switch to collection_search pgstac
jonhealy1 Apr 11, 2026
59b10e1
transaction routes scratch
jonhealy1 Apr 15, 2026
2cc1488
fix poly-hierarchy
jonhealy1 Apr 15, 2026
a3ac186
clean up tests
jonhealy1 Apr 15, 2026
2a5fed6
more test clean up
jonhealy1 Apr 15, 2026
a17e996
update docstrings
jonhealy1 Apr 16, 2026
d055d82
check, test links
jonhealy1 Apr 16, 2026
050fab2
lint
jonhealy1 Apr 16, 2026
c7fe5af
Merge branch 'main' into stac-fastapi-catalogs-extension
jonhealy1 Apr 22, 2026
4a9e45d
revert changes to compose, makefile
jonhealy1 Apr 22, 2026
7fec995
fix get all catalogs pagination
jonhealy1 Apr 22, 2026
df73ea7
qa fixes, pagination, items
jonhealy1 Apr 23, 2026
f95b8e5
qa, sub-catalogs
jonhealy1 Apr 23, 2026
19b0935
qa /children
jonhealy1 Apr 23, 2026
bfefc02
update tests
jonhealy1 Apr 23, 2026
9f5d2fa
qa catalog collections
jonhealy1 Apr 23, 2026
107a283
unlink sub-catalogs, collections
jonhealy1 Apr 23, 2026
ebc3411
lint, re factor links
jonhealy1 Apr 23, 2026
3e5c72a
lint
jonhealy1 Apr 23, 2026
d564167
lint
jonhealy1 Apr 23, 2026
c4defa8
ai review
jonhealy1 Apr 23, 2026
424014e
update changelog
jonhealy1 Apr 24, 2026
5af37fc
add to mkdocs
jonhealy1 Apr 24, 2026
f3d3e2d
return 409 conflict
jonhealy1 Apr 24, 2026
938e2f3
fix conformance classes
jonhealy1 Apr 24, 2026
4c5aec1
Merge branch 'main' into stac-fastapi-catalogs-extension
jonhealy1 May 2, 2026
8418971
fix parent_ids in collection
jonhealy1 May 2, 2026
07c7122
pop parent_ids from core collections routes
jonhealy1 May 2, 2026
623d068
fix self link logic
jonhealy1 May 2, 2026
5041db2
add items and queryables links
jonhealy1 May 2, 2026
b8479c9
lint
jonhealy1 May 2, 2026
f933623
use settings in app.py
jonhealy1 May 6, 2026
1372576
raise error
jonhealy1 May 6, 2026
71b4d03
ensure extension available in tests
jonhealy1 May 6, 2026
4f4dfef
update to catalogs extension v0.2.0
jonhealy1 May 6, 2026
0727347
add documentation
jonhealy1 May 6, 2026
5bd245a
change to ENABLE_CATALOGS_EXTENSION
jonhealy1 May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

- implement `neq` query operator ([#364](https://github.com/stac-utils/stac-fastapi-pgstac/pull/364))
- add api test for `neq` query operator ([#364](https://github.com/stac-utils/stac-fastapi-pgstac/pull/364))
- Multi-Tenant Catalogs Extension: Integrated optional `stac-fastapi-catalogs-extension` to support native DAG (Directed Acyclic Graph) traversal of Catalogs and Collections. Enabled via `ENABLE_CATALOGS_EXTENSION` environment variable ([#366](https://github.com/stac-utils/stac-fastapi-pgstac/pull/366))

### Fixed

Expand Down
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ COPY scripts/wait-for-it.sh scripts/wait-for-it.sh
COPY pyproject.toml pyproject.toml
COPY README.md README.md

RUN python -m pip install .[server]
RUN rm -rf stac_fastapi .toml README.md
RUN python -m pip install -e .[server,catalogs]

RUN groupadd -g 1000 user && \
useradd -u 1000 -g user -s /bin/bash -m user
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.tests
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ USER newuser
WORKDIR /app
COPY . /app

RUN python -m pip install . --user --group dev
RUN python -m pip install .[catalogs] --user --group dev
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ docker-shell:
test:
$(runtests) /bin/bash -c 'export && python -m pytest /app/tests/ --log-cli-level $(LOG_LEVEL)'

.PHONY: test-catalogs
test-catalogs:
$(runtests) python -m pytest /app/tests/extensions/test_catalogs.py -v --log-cli-level $(LOG_LEVEL)

.PHONY: run-database
run-database:
docker compose run --rm database
Expand All @@ -72,4 +76,4 @@ pytest: install

.PHONY: docs
docs:
uv run --group docs mkdocs build -f docs/mkdocs.yml
uv run --group docs mkdocs build -f docs/mkdocs.yml
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ To configure **stac-fastapi-pgstac** to [hydrate search result items at the API
| False | False | PgSTAC |
| True | True | API |

### Multi-Tenant Catalogs Extension

**stac-fastapi-pgstac** supports the optional [Multi-Tenant Catalogs Extension](https://github.com/StacLabs/multi-tenant-catalogs) for managing hierarchical catalog structures with support for Directed Acyclic Graphs (DAG).
This enables flexible catalog hierarchies where collections and catalogs can have multiple parents.

To enable this extension, install the `stac-fastapi-catalogs-extension` package and set the `ENABLE_CATALOGS_EXTENSION=TRUE` environment variable.

For write operations (creating, updating, and deleting catalogs, and linking/unlinking collections and catalogs), also set `ENABLE_TRANSACTIONS_EXTENSIONS=TRUE`.

For more details, see the [settings documentation](./docs/src/settings.md#multi-tenant-catalogs-extension).

### Migrations

There is a Python utility as part of PgSTAC ([pypgstac](https://stac-utils.github.io/pgstac/pypgstac/)) that includes a migration utility.
Expand Down
3 changes: 2 additions & 1 deletion compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ services:
- DB_MIN_CONN_SIZE=1
- DB_MAX_CONN_SIZE=1
- USE_API_HYDRATE=${USE_API_HYDRATE:-false}
- ENABLE_TRANSACTIONS_EXTENSIONS=TRUE
- ENABLE_TRANSACTIONS_EXTENSIONS=${ENABLE_TRANSACTIONS_EXTENSIONS:-false}
- ENABLE_CATALOGS_EXTENSION=TRUE
ports:
- "8082:8082"
volumes:
Expand Down
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ nav:
- db: api/stac_fastapi/pgstac/db.md
- extensions:
- module: api/stac_fastapi/pgstac/extensions/index.md
- catalogs: api/stac_fastapi/pgstac/extensions/catalogs.md
- filter: api/stac_fastapi/pgstac/extensions/filter.md
- query: api/stac_fastapi/pgstac/extensions/query.md
- models:
Expand Down
1 change: 1 addition & 0 deletions docs/src/api/stac_fastapi/pgstac/extensions/catalogs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: stac_fastapi.pgstac.extensions.catalogs
10 changes: 10 additions & 0 deletions docs/src/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ Example: `ENABLED_EXTENSIONS="pagination,sort"`

Since `6.0.0`, the transaction extension is not enabled by default. To add the transaction endpoints, users can set `ENABLE_TRANSACTIONS_EXTENSIONS=TRUE/YES/1`.

### Multi-Tenant Catalogs Extension

The optional Multi-Tenant Catalogs Extension provides discovery and management endpoints for a multi-tenant STAC architecture. It requires the `stac-fastapi-catalogs-extension` package to be installed.

For more information about the Multi-Tenant Catalogs specification, see [StacLabs/multi-tenant-catalogs](https://github.com/StacLabs/multi-tenant-catalogs).

To enable the catalogs extension, set `ENABLE_CATALOGS_EXTENSION=TRUE/YES/1`.

When `ENABLE_TRANSACTIONS_EXTENSIONS=TRUE`, additional write endpoints are available for creating, updating, and deleting catalogs and managing relationships (linking/unlinking catalogs and collections).

### Database config

- `PGUSER`: postgres username
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ validation = [
server = [
"uvicorn[standard]==0.38.0"
]
catalogs = [
"stac-fastapi-catalogs-extension==0.2.0",
]

[dependency-groups]
dev = [
Expand All @@ -68,6 +71,7 @@ dev = [
"pypgstac>=0.9,<0.10",
"requests",
"shapely",
"stac-fastapi-catalogs-extension==0.2.0",
"httpx",
"psycopg[pool,binary]==3.2.*",
"pre-commit",
Expand Down
53 changes: 52 additions & 1 deletion stac_fastapi/pgstac/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
If the variable is not set, enables all extensions.
"""

import logging
from contextlib import asynccontextmanager
from typing import cast

Expand Down Expand Up @@ -44,13 +45,31 @@
from stac_fastapi.pgstac.config import Settings
from stac_fastapi.pgstac.core import CoreCrudClient, health_check
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
from stac_fastapi.pgstac.extensions import FreeTextExtension, QueryExtension
from stac_fastapi.pgstac.extensions import (
CatalogsDatabaseLogic,
FreeTextExtension,
QueryExtension,
)
from stac_fastapi.pgstac.extensions.catalogs.catalogs_client import CatalogsClient
from stac_fastapi.pgstac.extensions.filter import FiltersClient
from stac_fastapi.pgstac.transactions import BulkTransactionsClient, TransactionsClient
from stac_fastapi.pgstac.types.search import PgstacSearch

logger = logging.getLogger(__name__)

# Optional catalogs extension (optional dependency)
try:
from stac_fastapi_catalogs_extension import (
CatalogsExtension,
CatalogsTransactionExtension,
)
except ImportError:
CatalogsExtension = None
CatalogsTransactionExtension = None

settings = Settings()


# search extensions
search_extensions_map: dict[str, ApiExtension] = {
"query": QueryExtension(),
Expand Down Expand Up @@ -153,6 +172,38 @@
collections_get_request_model = collection_search_extension.GET
application_extensions.append(collection_search_extension)

# Optional catalogs extension
logger.info("ENABLE_CATALOGS_EXTENSION is set to %s", settings.enable_catalogs_extension)

if settings.enable_catalogs_extension:
if CatalogsExtension is None or CatalogsTransactionExtension is None:
raise ImportError(
"ENABLE_CATALOGS_EXTENSION is set to true, but the catalogs extension is not installed. "
"Please install it with: pip install stac-fastapi-core[catalogs]."
)
try:
catalogs_client = CatalogsClient(database=CatalogsDatabaseLogic())

# Register the read-only catalogs extension
catalogs_extension = CatalogsExtension(
client=catalogs_client,
settings={"enable_response_models": True},
)
Comment thread
jonhealy1 marked this conversation as resolved.
application_extensions.append(catalogs_extension)
logger.info("CatalogsExtension (read-only) enabled successfully.")

# Register the transaction extension if transactions are enabled
if with_transactions:
catalogs_transaction_extension = CatalogsTransactionExtension(
client=catalogs_client,
settings={"enable_response_models": True},
)
application_extensions.append(catalogs_transaction_extension)
logger.info("CatalogsTransactionExtension enabled successfully.")
except Exception as e: # pragma: no cover - defensive
logger.error("Failed to initialize Catalogs extensions: %s", e)
raise


@asynccontextmanager
async def lifespan(app: FastAPI):
Expand Down
1 change: 1 addition & 0 deletions stac_fastapi/pgstac/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class Settings(ApiSettings):

enabled_extensions: str = ""
enable_transactions_extensions: bool = False
enable_catalogs_extension: bool = False
validate_extensions: bool = False
"""
Validate `stac_extensions` schemas against submitted data when creating or updated STAC objects.
Expand Down
6 changes: 6 additions & 0 deletions stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ async def all_collections( # type: ignore [override] # noqa: C901
}
)

# Remove internal metadata
collection.pop("parent_ids", None) # type: ignore [typeddict-item]

collections["links"] = await CollectionSearchPagingLinks(
request=request, next=next_link, prev=prev_link
).get_links()
Expand Down Expand Up @@ -206,6 +209,9 @@ async def get_collection( # type: ignore [override]
}
)

# Remove internal metadata
collection.pop("parent_ids", None) # type: ignore [typeddict-item]

return collection

async def _get_base_item(
Expand Down
10 changes: 9 additions & 1 deletion stac_fastapi/pgstac/extensions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
"""pgstac extension customisations."""

from .catalogs.catalogs_client import CatalogsClient
from .catalogs.catalogs_database_logic import CatalogsDatabaseLogic
from .filter import FiltersClient
from .free_text import FreeTextExtension
from .query import QueryExtension

__all__ = ["QueryExtension", "FiltersClient", "FreeTextExtension"]
__all__ = [
"QueryExtension",
"FiltersClient",
"FreeTextExtension",
"CatalogsClient",
"CatalogsDatabaseLogic",
]
13 changes: 13 additions & 0 deletions stac_fastapi/pgstac/extensions/catalogs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Catalogs extension for pgstac."""

from .catalogs_client import CatalogsClient
from .catalogs_database_logic import CatalogsDatabaseLogic
from .catalogs_links import CatalogLinks, ChildLinks, SubCatalogLinks

__all__ = [
"CatalogsClient",
"CatalogsDatabaseLogic",
"CatalogLinks",
"ChildLinks",
"SubCatalogLinks",
]
Loading
Loading