Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.10" # stac-api-validator requires >= 3.10
python-version: "3.13" # stac-api-validator requires >= 3.10
cache: "pip"

- name: API Validator
Expand Down
37 changes: 24 additions & 13 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
services:

stac:
platform: linux/amd64
image: pc-apis-stac
Expand All @@ -17,7 +16,7 @@ services:
- azurite
- redis
command: >
bash -c "pypgstac pgready && uvicorn pcstac.main:app --host 0.0.0.0 --port 8081 --reload --proxy-headers --root-path '/stac'"
bash -c "pypgstac pgready && uvicorn pcstac.main:app --host 0.0.0.0 --port 8081 --reload --proxy-headers --root-path /stac"

tiler:
image: pc-apis-tiler
Expand All @@ -29,7 +28,7 @@ services:
dockerfile: pctiler/Dockerfile
env_file: ${PC_TILER_ENV_FILE:-./pc-tiler.dev.env}
environment:
# Allow proxied managed identity requests in dev
# Allow proxied managed identity requests in dev
- IDENTITY_ENDPOINT=http://token-proxy:8086/dev/token
- IMDS_ENDPOINT=active
ports:
Expand All @@ -40,7 +39,19 @@ services:
- ./pccommon:/opt/src/pccommon
depends_on:
- database
command: [ "uvicorn", "pctiler.main:app", "--host", "0.0.0.0", "--port", "8082", "--reload", "--proxy-headers", "--root-path", "/data" ]
command:
[
"uvicorn",
"pctiler.main:app",
"--host",
"0.0.0.0",
"--port",
"8082",
"--reload",
"--proxy-headers",
"--root-path",
"/data",
]

funcs:
image: pc-apis-funcs
Expand All @@ -58,11 +69,8 @@ services:
- ~/.azure:/home/.azure

nginx:
image: pc-apis-nginx
image: nginx:1.29.4
container_name: pc-apis-nginx
build:
context: ./nginx
dockerfile: Dockerfile
links:
- database
- azurite
Expand All @@ -78,14 +86,16 @@ services:

database:
container_name: pc-stac-db
image: pc-apis-stac-db
build:
context: ./pgstac
dockerfile: Dockerfile
platform: linux/amd64
image: postgis/postgis:17-3.5
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=postgis
- POSTGIS_MAJOR=3
- PGUSER=postgres
- PGDATABASE=postgres
- PGHOST=localhost
ports:
- "5432:5432"
volumes:
Expand All @@ -106,7 +116,8 @@ services:
container_name: pcapis-azurite
image: mcr.microsoft.com/azure-storage/azurite:3.35.0
hostname: azurite
command: "azurite --silent --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost
command:
"azurite --silent --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost
0.0.0.0 -l /workspace"
ports:
- "10000:10000" # Blob
Expand Down
4 changes: 0 additions & 4 deletions nginx/Dockerfile

This file was deleted.

1 change: 0 additions & 1 deletion pc-stac.dev.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
APP_ROOT_PATH=/stac
APP_HOST=0.0.0.0
APP_PORT=8081
FORWARDED_ALLOW_IPS=*
Expand Down
26 changes: 0 additions & 26 deletions pcstac/pcstac/api.py

This file was deleted.

89 changes: 84 additions & 5 deletions pcstac/pcstac/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
from fastapi import HTTPException, Request
from stac_fastapi.pgstac.core import CoreCrudClient
from stac_fastapi.types.errors import NotFoundError
from stac_fastapi.types.requests import get_base_url
from stac_fastapi.types.stac import (
Collection,
Collections,
Item,
ItemCollection,
LandingPage,
)
from stac_pydantic.links import Relations
from stac_pydantic.shared import MimeTypes

from pccommon.config import get_all_render_configs, get_render_config
from pccommon.config.collections import DefaultRenderConfig
Expand Down Expand Up @@ -220,7 +223,7 @@ async def _fetch() -> ItemCollection:
search_request.collections is None
and "collection=" not in str(request.url)
and '{"property":"collection"}'
not in orjson.dumps(search_request.filter).decode("utf-8")
not in orjson.dumps(search_request.filter_expr).decode("utf-8")
Copy link
Collaborator Author

@vincentsarago vincentsarago Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed filter to filter_expr input attributes in GET endpoint methods

ref: https://github.com/stac-utils/stac-fastapi-pgstac/blob/main/CHANGES.md#400---2025-02-03

):
raise HTTPException(status_code=422, detail="collection is required")

Expand All @@ -238,11 +241,87 @@ async def _fetch() -> ItemCollection:
return await cached_result(_fetch, cache_key, request)

async def landing_page(self, request: Request, **kwargs: Any) -> LandingPage:
_super: CoreCrudClient = super()
"""Landing page."""

async def _fetch() -> LandingPage:
landing = await _super.landing_page(request=request, **kwargs)
return landing
"""Landing page.

NOTE: we need a custom landing page implementation
to avoid the call to `all_collections` method.

TODO: replace this with:
```
_super: CoreCrudClient = super()

async def _fetch() -> LandingPage:
landing = await _super.landing_page(request=request, **kwargs)
return landing
```
when switching to stac-fastapi >=v5.1.

"""
base_url = get_base_url(request)

landing_page = self._landing_page(
base_url=base_url,
conformance_classes=self.conformance_classes(),
extension_schemas=[],
)

# Add Queryables link
if self.extension_is_enabled(
"FilterExtension"
) or self.extension_is_enabled("SearchFilterExtension"):
landing_page["links"].append(
{
"rel": Relations.queryables.value,
"type": MimeTypes.jsonschema.value,
"title": "Queryables available for this Catalog",
"href": urljoin(base_url, "queryables"),
"method": "GET",
}
)

# Add Aggregation links
if self.extension_is_enabled("AggregationExtension"):
landing_page["links"].extend(
[
{
"rel": "aggregate",
"type": "application/json",
"title": "Aggregate",
"href": urljoin(base_url, "aggregate"),
},
{
"rel": "aggregations",
"type": "application/json",
"title": "Aggregations",
"href": urljoin(base_url, "aggregations"),
},
]
)

# Add OpenAPI URL
landing_page["links"].append(
{
"rel": Relations.service_desc.value,
"type": MimeTypes.openapi.value,
"title": "OpenAPI service description",
"href": str(request.url_for("openapi")),
}
)

# Add human readable service-doc
landing_page["links"].append(
{
"rel": Relations.service_doc.value,
"type": MimeTypes.html.value,
"title": "OpenAPI service documentation",
"href": str(request.url_for("swagger_ui_html")),
}
)

return LandingPage(**landing_page)

return await cached_result(_fetch, CACHE_KEY_LANDING_PAGE, request)

Expand Down Expand Up @@ -303,6 +382,6 @@ def create(
title=API_TITLE,
description=API_DESCRIPTION,
extra_conformance_classes=extra_conformance_classes,
post_request_model=post_request_model,
pgstac_search_model=post_request_model,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed post_request_model attribute to pgstac_search_model in CoreCrudClient class

ref: https://github.com/stac-utils/stac-fastapi-pgstac/blob/main/CHANGES.md#400---2025-02-03

)
return it
2 changes: 1 addition & 1 deletion pcstac/pcstac/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
client=PCFiltersClient(),
conformance_classes=[
FilterConformanceClasses.FILTER,
FilterConformanceClasses.ITEM_SEARCH_FILTER,
FilterConformanceClasses.SEARCH,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed filter.FilterConformanceClasses.ITEM_SEARCH_FILTER -> filter.FilterConformanceClasses.SEARCH

ref: renamed filter.FilterConformanceClasses.ITEM_SEARCH_FILTER -> filter.FilterConformanceClasses.SEARCH

FilterConformanceClasses.BASIC_CQL2,
FilterConformanceClasses.CQL2_JSON,
FilterConformanceClasses.CQL2_TEXT,
Expand Down
16 changes: 12 additions & 4 deletions pcstac/pcstac/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from fastapi.exceptions import RequestValidationError, StarletteHTTPException
from fastapi.openapi.utils import get_openapi
from fastapi.responses import ORJSONResponse
from stac_fastapi.api.app import StacApi as PCStacApi
from stac_fastapi.api.errors import DEFAULT_STATUS_CODES
from stac_fastapi.api.middleware import ProxyHeaderMiddleware
from stac_fastapi.api.models import (
Expand All @@ -29,13 +30,13 @@
from pccommon.middleware import TraceMiddleware, add_timeout, http_exception_handler
from pccommon.openapi import fixup_schema
from pccommon.redis import connect_to_redis
from pcstac.api import PCStacApi
from pcstac.client import PCClient
from pcstac.config import (
API_DESCRIPTION,
API_TITLE,
API_VERSION,
EXTENSIONS,
STAC_API_VERSION,
get_settings,
)
from pcstac.errors import PC_DEFAULT_STATUS_CODES
Expand Down Expand Up @@ -92,6 +93,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
db_min_conn_size=app_settings.db_min_conn_size,
base_item_cache=RedisBaseItemCache,
debug=DEBUG,
root_path=APP_ROOT_PATH,
),
client=PCClient.create(post_request_model=search_post_request_model),
extensions=EXTENSIONS,
Expand Down Expand Up @@ -148,9 +150,15 @@ def custom_openapi() -> Dict[str, Any]:
return app.openapi_schema
else:
schema = get_openapi(
title="Planetary Computer STAC API",
title=API_TITLE,
version=app_settings.api_version,
routes=app.routes,
)
app.openapi_schema = fixup_schema(app.root_path, schema)
return schema
fixed_schema = fixup_schema(
app.root_path, schema, tag=f"STAC API {STAC_API_VERSION}"
)
app.openapi_schema = fixed_schema
return fixed_schema
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is maybe the biggest change with this PR that doesn't seem well tested in tests



app.openapi = custom_openapi # type: ignore
32 changes: 21 additions & 11 deletions pcstac/pcstac/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from stac_fastapi.api.models import BaseSearchGetRequest, ItemCollectionUri
from stac_fastapi.pgstac.types.base_item_cache import BaseItemCache
from stac_fastapi.pgstac.types.search import PgstacSearch
from stac_fastapi.types.rfc3339 import DateTimeType, str_to_interval
from stac_fastapi.types.search import DateTimeQueryType, Limit, _validate_datetime
from starlette.requests import Request
from typing_extensions import Annotated

Expand Down Expand Up @@ -71,21 +71,31 @@ async def _fetch() -> Dict[str, Any]:

@attr.s
class PCItemCollectionUri(ItemCollectionUri):
limit: Annotated[Optional[int], Query()] = attr.ib(
default=LEGACY_ITEM_DEFAULT_LIMIT
)
limit: Annotated[
Optional[Limit],
Query(
description="Limits the number of results that are included in each page of the response (capped to 10_000)." # noqa: E501
),
] = attr.ib(default=LEGACY_ITEM_DEFAULT_LIMIT)


def patch_and_convert(interval: Optional[str]) -> Optional[DateTimeType]:
def patch_and_convert(value: Optional[str]) -> Optional[str]:
"""Patch datetime to add hh-mm-ss and timezone info."""
if interval:
interval = _patch_datetime(interval)
return str_to_interval(interval)
if value:
value = _patch_datetime(value)
return value


@attr.s
class PCSearchGetRequest(BaseSearchGetRequest):
datetime: Annotated[Optional[DateTimeType], Query()] = attr.ib(
default=None, converter=patch_and_convert
datetime: DateTimeQueryType = attr.ib(
default=None,
converter=patch_and_convert,
validator=_validate_datetime,
)
limit: Annotated[Optional[int], Query()] = attr.ib(default=DEFAULT_LIMIT)
limit: Annotated[
Optional[Limit],
Query(
description="Limits the number of results that are included in each page of the response (capped to 10_000)." # noqa: E501
),
] = attr.ib(default=DEFAULT_LIMIT)
10 changes: 5 additions & 5 deletions pcstac/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ requires-python = ">=3.7"
dependencies = [
"idna>=3.7.0",
"orjson==3.10.4",
"pypgstac[psycopg]>=0.8.5,<0.9",
"pypgstac[psycopg]==0.9.6",
"pystac==1.10.1",
"stac-fastapi.api==3.0.0b2",
"stac-fastapi.extensions==3.0.0b2",
"stac-fastapi.pgstac==3.0.0a4",
"stac-fastapi.types==3.0.0b2",
"stac-fastapi.api==5.0.3",
"stac-fastapi.extensions==5.0.3",
"stac-fastapi.pgstac==4.0.4",
"stac-fastapi.types==5.0.3",
"typing_extensions>=4.6.1",
"urllib3>=2.2.2",
]
Expand Down
Loading