Skip to content

Commit

Permalink
Merge pull request #21 from developmentseed/feature/update-stac-requi…
Browse files Browse the repository at this point in the history
…rements

update stac-fastapi-pgstac to 4.0
  • Loading branch information
vincentsarago authored Feb 4, 2025
2 parents 976fbe8 + 41b55b2 commit 9f950ba
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 43 deletions.
3 changes: 2 additions & 1 deletion infrastructure/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def __init__(
custom_resource_properties={
"context": True,
"mosaic_index": True,
"pgstac_version": "0.9.2",
},
)

Expand Down Expand Up @@ -187,7 +188,7 @@ def __init__(
"NAME": app_config.build_service_name("stac"),
"description": f"{app_config.stage} STAC API",
"TITILER_ENDPOINT": raster.url.strip("/"),
"EXTENSIONS": '["filter", "query", "sort", "fields", "pagination", "titiler"]',
"EXTENSIONS": '["filter", "query", "sort", "fields", "pagination", "titiler", "collection_search", "free_text"]',
},
db=pgstac_db.connection_target,
db_secret=pgstac_db.pgstac_secret,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies = []
[dependency-groups]
deploy = [
"boto3==1.24.15",
"eoapi-cdk==7.4.2",
"eoapi-cdk==7.5.0",
"pydantic-settings[yaml]==2.2.1",
"pydantic==2.7",
"typing-extensions>=4.12.2",
Expand Down
143 changes: 104 additions & 39 deletions runtimes/eoapi/stac/eoapi/stac/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@
from fastapi.responses import ORJSONResponse
from stac_fastapi.api.app import StacApi
from stac_fastapi.api.models import (
EmptyRequest,
ItemCollectionUri,
create_get_request_model,
create_post_request_model,
create_request_model,
)
from stac_fastapi.extensions.core import (
CollectionSearchExtension,
CollectionSearchFilterExtension,
FieldsExtension,
FilterExtension,
FreeTextExtension,
ItemCollectionFilterExtension,
OffsetPaginationExtension,
SearchFilterExtension,
SortExtension,
TokenPaginationExtension,
TransactionExtension,
)
from stac_fastapi.extensions.core.fields import FieldsConformanceClasses
from stac_fastapi.extensions.core.free_text import FreeTextConformanceClasses
from stac_fastapi.extensions.core.query import QueryConformanceClasses
from stac_fastapi.extensions.core.sort import SortConformanceClasses
from stac_fastapi.extensions.third_party import BulkTransactionExtension
from stac_fastapi.pgstac.core import CoreCrudClient
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
Expand Down Expand Up @@ -52,52 +62,119 @@
auth_settings = OpenIdConnectSettings()
settings = api_settings.load_postgres_settings()

enabled_extensions = api_settings.extensions or []

# Logs
init_logging(debug=api_settings.debug)
logger = logging.getLogger(__name__)

# Extensions
extensions_map = {
# application extensions
application_extensions_map = {
"transaction": TransactionExtension(
client=TransactionsClient(),
settings=settings,
response_class=ORJSONResponse,
),
"bulk_transactions": BulkTransactionExtension(client=BulkTransactionsClient()),
}
if "titiler" in enabled_extensions and api_settings.titiler_endpoint:
application_extensions_map["titiler"] = TiTilerExtension(
titiler_endpoint=api_settings.titiler_endpoint
)

# search extensions
search_extensions_map = {
"query": QueryExtension(),
"sort": SortExtension(),
"fields": FieldsExtension(),
"filter": SearchFilterExtension(client=FiltersClient()),
"pagination": TokenPaginationExtension(),
"filter": FilterExtension(client=FiltersClient()),
"bulk_transactions": BulkTransactionExtension(client=BulkTransactionsClient()),
"titiler": (
TiTilerExtension(titiler_endpoint=api_settings.titiler_endpoint)
if api_settings.titiler_endpoint
else None
}

# collection_search extensions
cs_extensions_map = {
"query": QueryExtension(conformance_classes=[QueryConformanceClasses.COLLECTIONS]),
"sort": SortExtension(conformance_classes=[SortConformanceClasses.COLLECTIONS]),
"fields": FieldsExtension(
conformance_classes=[FieldsConformanceClasses.COLLECTIONS]
),
"filter": CollectionSearchFilterExtension(client=FiltersClient()),
"free_text": FreeTextExtension(
conformance_classes=[FreeTextConformanceClasses.COLLECTIONS],
),
"pagination": OffsetPaginationExtension(),
}

# item_collection extensions
itm_col_extensions_map = {
"query": QueryExtension(
conformance_classes=[QueryConformanceClasses.ITEMS],
),
"sort": SortExtension(
conformance_classes=[SortConformanceClasses.ITEMS],
),
"fields": FieldsExtension(conformance_classes=[FieldsConformanceClasses.ITEMS]),
"filter": ItemCollectionFilterExtension(client=FiltersClient()),
"pagination": TokenPaginationExtension(),
}

if enabled_extensions := api_settings.extensions:
extensions = [
extensions_map.get(name)
for name in enabled_extensions
if name in extensions_map
application_extensions = [
extension
for key, extension in application_extensions_map.items()
if key in enabled_extensions
]

# Request Models
# /search models
search_extensions = [
extension
for key, extension in search_extensions_map.items()
if key in enabled_extensions
]
post_request_model = create_post_request_model(
search_extensions, base_model=PgstacSearch
)
get_request_model = create_get_request_model(search_extensions)
application_extensions.extend(search_extensions)

# /collections/{collectionId}/items model
items_get_request_model = ItemCollectionUri
itm_col_extensions = [
extension
for key, extension in itm_col_extensions_map.items()
if key in enabled_extensions
]
if itm_col_extensions:
items_get_request_model = create_request_model(
model_name="ItemCollectionUri",
base_model=ItemCollectionUri,
extensions=itm_col_extensions,
request_type="GET",
)
application_extensions.extend(itm_col_extensions)

# /collections model
collections_get_request_model = EmptyRequest
if "collection_search" in enabled_extensions:
cs_extensions = [
extension
for key, extension in cs_extensions_map.items()
if key in enabled_extensions
]
else:
extensions = list(extensions_map.values())
collection_search_extension = CollectionSearchExtension.from_extensions(
cs_extensions
)
collections_get_request_model = collection_search_extension.GET
application_extensions.append(collection_search_extension)


@asynccontextmanager
async def lifespan(app: FastAPI):
"""FastAPI Lifespan."""
logger.debug("Connecting to db...")
await connect_to_db(app)
logger.debug("Connected to db.")

yield

logger.debug("Closing db connections...")
await close_db_connection(app)
logger.debug("Closed db connection.")


# Middlewares
Expand All @@ -113,19 +190,6 @@ async def lifespan(app: FastAPI):
)
)

# Custom Models
items_get_model = ItemCollectionUri
if any(isinstance(ext, TokenPaginationExtension) for ext in extensions):
items_get_model = create_request_model(
model_name="ItemCollectionUri",
base_model=ItemCollectionUri,
mixins=[TokenPaginationExtension().GET],
request_type="GET",
)

search_get_model = create_get_request_model(extensions)
search_post_model = create_post_request_model(extensions, base_model=PgstacSearch)

api = StacApi(
app=FastAPI(
title=api_settings.name,
Expand All @@ -141,11 +205,12 @@ async def lifespan(app: FastAPI):
title=api_settings.name,
description=api_settings.name,
settings=settings,
extensions=extensions,
client=CoreCrudClient(post_request_model=search_post_model),
items_get_request_model=items_get_model,
search_get_request_model=search_get_model,
search_post_request_model=search_post_model,
extensions=application_extensions,
client=CoreCrudClient(pgstac_search_model=post_request_model),
items_get_request_model=items_get_request_model,
search_get_request_model=get_request_model,
search_post_request_model=post_request_model,
collections_get_request_model=collections_get_request_model,
response_class=ORJSONResponse,
middlewares=middlewares,
)
Expand Down
3 changes: 3 additions & 0 deletions runtimes/eoapi/stac/eoapi/stac/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ class ApiSettings(BaseSettings):
"fields",
"pagination",
"titiler",
"free_text",
"transaction",
# "bulk_transactions",
"collection_search",
]

@field_validator("cors_origins")
Expand Down
2 changes: 1 addition & 1 deletion runtimes/eoapi/stac/eoapi/stac/templates/stac-viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@
return e;
})

if (data.context.matched === 0) {
if (data.numberMatched === 0) {
throw Error("No item found")
}

Expand Down
2 changes: 1 addition & 1 deletion runtimes/eoapi/stac/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ classifiers = [
]
dynamic = ["version"]
dependencies = [
"stac-fastapi.pgstac>=3.0,<3.1",
"stac-fastapi.pgstac>=4.0,<4.1",
"jinja2>=2.11.2,<4.0.0",
"starlette-cramjam>=0.4,<0.5",
"psycopg_pool",
Expand Down

0 comments on commit 9f950ba

Please sign in to comment.