Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (stac): enable transaction extensions #163

Merged
merged 3 commits into from
Nov 27, 2023
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: 6 additions & 0 deletions docker-compose.custom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ services:
# https://github.com/developmentseed/eoAPI/issues/16
# - TITILER_ENDPOINT=raster
- TITILER_ENDPOINT=http://127.0.0.1:8082
# PgSTAC extensions
# - EOAPI_STAC_EXTENSIONS=["filter", "query", "sort", "fields", "pagination", "context", "transaction"]
# - EOAPI_STAC_CORS_METHODS='GET,POST,PUT,OPTIONS'
depends_on:
- database
- raster
Expand Down Expand Up @@ -171,6 +174,9 @@ services:
# https://github.com/developmentseed/eoAPI/issues/16
# - TITILER_ENDPOINT=raster
- TITILER_ENDPOINT=http://127.0.0.1:8082
# PgSTAC extensions
# - EOAPI_STAC_EXTENSIONS=["filter", "query", "sort", "fields", "pagination", "context", "transaction"]
# - EOAPI_STAC_CORS_METHODS='GET,POST,PUT,OPTIONS'
depends_on:
- database
- raster-uvicorn
Expand Down
20 changes: 15 additions & 5 deletions runtime/eoapi/stac/eoapi/stac/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
from contextlib import asynccontextmanager

from eoapi.stac.config import ApiSettings, TilesApiSettings
from eoapi.stac.config import extensions as PgStacExtensions
from eoapi.stac.config import get_request_model as GETModel
from eoapi.stac.config import post_request_model as POSTModel
from eoapi.stac.extension import TiTilerExtension
from eoapi.stac.extension import extensions_map as PgStacExtensions
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
from stac_fastapi.api.app import StacApi
from stac_fastapi.api.models import create_get_request_model, create_post_request_model
from stac_fastapi.pgstac.config import Settings
from stac_fastapi.pgstac.core import CoreCrudClient
from stac_fastapi.pgstac.db import close_db_connection, connect_to_db
from stac_fastapi.pgstac.types.search import PgstacSearch
from starlette.middleware.cors import CORSMiddleware
from starlette.requests import Request
from starlette.responses import HTMLResponse
Expand Down Expand Up @@ -43,12 +43,22 @@ async def lifespan(app: FastAPI):
await close_db_connection(app)


if enabled_extensions := api_settings.extensions:
extensions = [
PgStacExtensions[extension_name] for extension_name in enabled_extensions
]
else:
extensions = list(PgStacExtensions.values())

POSTModel = create_post_request_model(extensions, base_model=PgstacSearch)
GETModel = create_get_request_model(extensions)

api = StacApi(
app=FastAPI(title=api_settings.name, lifespan=lifespan),
title=api_settings.name,
description=api_settings.name,
settings=settings,
extensions=PgStacExtensions,
extensions=extensions,
client=CoreCrudClient(post_request_model=POSTModel),
search_get_request_model=GETModel,
search_post_request_model=POSTModel,
Expand All @@ -63,7 +73,7 @@ async def lifespan(app: FastAPI):
CORSMiddleware,
allow_origins=api_settings.cors_origins,
allow_credentials=True,
allow_methods=["GET", "POST", "OPTIONS"],
allow_methods=api_settings.cors_methods,
allow_headers=["*"],
)

Expand Down
42 changes: 16 additions & 26 deletions runtime/eoapi/stac/eoapi/stac/config.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
"""API settings."""

from functools import lru_cache
from typing import Optional
from typing import List, Optional

import pydantic
from stac_fastapi.api.models import create_get_request_model, create_post_request_model
from stac_fastapi.extensions.core import (
ContextExtension,
FieldsExtension,
FilterExtension,
QueryExtension,
SortExtension,
TokenPaginationExtension,
)
from stac_fastapi.pgstac.extensions.filter import FiltersClient
from stac_fastapi.pgstac.types.search import PgstacSearch


class _ApiSettings(pydantic.BaseSettings):
"""API settings"""

name: str = "eoAPI-stac"
cors_origins: str = "*"
cors_methods: str = "GET,POST,OPTIONS"
cachecontrol: str = "public, max-age=3600"
debug: bool = False

extensions: List[str] = [
"filter",
"query",
"sort",
"fields",
"pagination",
"context",
]
emileten marked this conversation as resolved.
Show resolved Hide resolved

@pydantic.validator("cors_origins")
def parse_cors_origin(cls, v):
"""Parse CORS origins."""
return [origin.strip() for origin in v.split(",")]

@pydantic.validator("cors_methods")
def parse_cors_methods(cls, v):
"""Parse CORS methods."""
return [method.strip() for method in v.split(",")]

class Config:
"""model config"""

Expand Down Expand Up @@ -69,17 +73,3 @@ def TilesApiSettings() -> _TilesApiSettings:

"""
return _TilesApiSettings()


extensions = [
FilterExtension(
client=FiltersClient(),
),
QueryExtension(),
SortExtension(),
FieldsExtension(),
TokenPaginationExtension(),
ContextExtension(),
]
post_request_model = create_post_request_model(extensions, base_model=PgstacSearch)
get_request_model = create_get_request_model(extensions)
46 changes: 45 additions & 1 deletion runtime/eoapi/stac/eoapi/stac/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,58 @@
from urllib.parse import urlencode

import attr
import pydantic
from fastapi import APIRouter, FastAPI, HTTPException, Path, Query
from fastapi.responses import RedirectResponse
from fastapi.responses import ORJSONResponse, RedirectResponse
from stac_fastapi.extensions.core import (
ContextExtension,
FieldsExtension,
FilterExtension,
QueryExtension,
SortExtension,
TokenPaginationExtension,
TransactionExtension,
)
from stac_fastapi.extensions.third_party import BulkTransactionExtension
from stac_fastapi.pgstac.extensions.filter import FiltersClient
from stac_fastapi.pgstac.transactions import BulkTransactionsClient, TransactionsClient
from stac_fastapi.types.extension import ApiExtension
from starlette.requests import Request

router = APIRouter()


class TransactionSettings(pydantic.BaseSettings):
"""Simple API settings from stac-fastapi-pgstac Transaction Client.

ref: https://github.com/stac-utils/stac-fastapi/blob/09dac221d86fe70035aa6cddbc9a3f0de304aff5/stac_fastapi/types/stac_fastapi/types/config.py#L7-L37
"""

enable_response_models: bool = False

class Config:
"""Model config (https://pydantic-docs.helpmanual.io/usage/model_config/)."""

extra = "allow"
env_file = ".env"


extensions_map = {
"query": QueryExtension(),
"sort": SortExtension(),
"fields": FieldsExtension(),
"pagination": TokenPaginationExtension(),
"context": ContextExtension(),
"filter": FilterExtension(client=FiltersClient()),
"transaction": TransactionExtension(
client=TransactionsClient(),
settings=TransactionSettings(),
response_class=ORJSONResponse,
),
"bulk_transactions": BulkTransactionExtension(client=BulkTransactionsClient()),
}
emileten marked this conversation as resolved.
Show resolved Hide resolved


@attr.s
class TiTilerExtension(ApiExtension):
"""TiTiler extension."""
Expand Down