From 213fceccbc3d0aefde5bdd703579738a99d9af79 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Thu, 18 Jul 2024 08:54:54 -0600 Subject: [PATCH 01/22] initial changes for titiler pgstac v1 upgrade --- raster_api/runtime/setup.py | 2 +- raster_api/runtime/src/app.py | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/raster_api/runtime/setup.py b/raster_api/runtime/setup.py index 624e0a75..25dfce4c 100644 --- a/raster_api/runtime/setup.py +++ b/raster_api/runtime/setup.py @@ -8,7 +8,7 @@ inst_reqs = [ "boto3", "rio-tiler==6.5.0", - "titiler.pgstac==0.8.3", + "titiler.pgstac==1.3.0", "titiler.core>=0.15.5,<0.16", "titiler.mosaic>=0.15.5,<0.16", "titiler.extensions[cogeo]>=0.15.5,<0.16", diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 7a2d03a4..7de2f7ed 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -7,7 +7,7 @@ from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings from src.dependencies import ColorMapParams, ItemPathParams -from src.extensions import stacViewerExtension +from src.extensions import searchInfoExtension, stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -23,7 +23,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db -from titiler.pgstac.factory import MosaicTilerFactory +from titiler.pgstac.factory import MosaicTilerFactory, add_search_register_route, add_mosaic_register_route from titiler.pgstac.reader import PgSTACReader logging.getLogger("botocore.credentials").disabled = True @@ -67,7 +67,8 @@ async def lifespan(app: FastAPI): # /mosaic - PgSTAC Mosaic titiler endpoint ############################################################################### mosaic = MosaicTilerFactory( - router_prefix="/mosaic", + router_prefix="/mosaic/{search_id}", + path_dependency=ItemPathParams, optional_headers=optional_headers, environment_dependency=settings.get_gdal_config, process_dependency=PostProcessParams, @@ -81,10 +82,32 @@ async def lifespan(app: FastAPI): # add /bbox [GET] and /feature [POST] (default to False) add_part=True, colormap_dependency=ColorMapParams, + extensions=[ + searchInfoExtension(), + ] ) -app.include_router(mosaic.router, prefix="/mosaic", tags=["Mosaic"]) -# TODO -# prefix will be replaced by `/mosaics/{search_id}` in titiler-pgstac 1.0.0 +app.include_router(mosaic.router, prefix="/mosaic/{search_id}", tags=["Mosaic"]) + +add_search_register_route( + app, + # any dependency we want to validate + # when creating the tilejson/map links + tile_dependencies=[ + mosaic.layer_dependency, + mosaic.dataset_dependency, + mosaic.pixel_selection_dependency, + mosaic.process_dependency, + mosaic.rescale_dependency, + mosaic.colormap_dependency, + mosaic.render_dependency, + mosaic.pgstac_dependency, + mosaic.reader_dependency, + mosaic.backend_dependency, + ], +) +# add /list endpoint +add_search_register_route(app) + ############################################################################### # /stac - Custom STAC titiler endpoint From 6361c8dd361bcdb7df135862b062dfdcbb65f896 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Thu, 18 Jul 2024 09:40:16 -0600 Subject: [PATCH 02/22] format --- raster_api/runtime/src/app.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 7de2f7ed..e4964a2e 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -7,7 +7,7 @@ from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings from src.dependencies import ColorMapParams, ItemPathParams -from src.extensions import searchInfoExtension, stacViewerExtension +from src.extensions import searchInfoExtension, stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -23,7 +23,11 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db -from titiler.pgstac.factory import MosaicTilerFactory, add_search_register_route, add_mosaic_register_route +from titiler.pgstac.factory import ( + MosaicTilerFactory, + add_mosaic_register_route, + add_search_register_route, +) from titiler.pgstac.reader import PgSTACReader logging.getLogger("botocore.credentials").disabled = True @@ -84,7 +88,7 @@ async def lifespan(app: FastAPI): colormap_dependency=ColorMapParams, extensions=[ searchInfoExtension(), - ] + ], ) app.include_router(mosaic.router, prefix="/mosaic/{search_id}", tags=["Mosaic"]) From 12ec468f086a0be0d058bbb5945ddf36430bba88 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Thu, 18 Jul 2024 09:48:34 -0600 Subject: [PATCH 03/22] add add_search_list_route --- raster_api/runtime/src/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index e4964a2e..da8abf31 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -25,7 +25,7 @@ from titiler.pgstac.db import close_db_connection, connect_to_db from titiler.pgstac.factory import ( MosaicTilerFactory, - add_mosaic_register_route, + add_search_list_route, add_search_register_route, ) from titiler.pgstac.reader import PgSTACReader @@ -110,7 +110,7 @@ async def lifespan(app: FastAPI): ], ) # add /list endpoint -add_search_register_route(app) +add_search_list_route(app) ############################################################################### From 47ffa3d446631ee9bf3283ac6790a7e2e22b2624 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Fri, 19 Jul 2024 07:03:51 -0600 Subject: [PATCH 04/22] update titiler.core --- raster_api/runtime/setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/raster_api/runtime/setup.py b/raster_api/runtime/setup.py index 25dfce4c..d2860fc8 100644 --- a/raster_api/runtime/setup.py +++ b/raster_api/runtime/setup.py @@ -9,9 +9,9 @@ "boto3", "rio-tiler==6.5.0", "titiler.pgstac==1.3.0", - "titiler.core>=0.15.5,<0.16", - "titiler.mosaic>=0.15.5,<0.16", - "titiler.extensions[cogeo]>=0.15.5,<0.16", + "titiler.core>=0.18.5,<0.19", + "titiler.mosaic>=0.18.5,<0.19", + "titiler.extensions[cogeo]>=0.18.5,<0.19", "starlette-cramjam>=0.3,<0.4", "aws_xray_sdk>=2.6.0,<3", "aws-lambda-powertools>=1.18.0", From 9342294da0e3a0d773a7f8749a164c996b1c3110 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 19 Jul 2024 18:12:31 +0200 Subject: [PATCH 05/22] fix jinja2 template --- raster_api/runtime/src/app.py | 3 ++- raster_api/runtime/src/extensions.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index da8abf31..6d65ab00 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -7,7 +7,7 @@ from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings from src.dependencies import ColorMapParams, ItemPathParams -from src.extensions import searchInfoExtension, stacViewerExtension +from src.extensions import stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -23,6 +23,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db +from titiler.pgstac.extensions import searchInfoExtension from titiler.pgstac.factory import ( MosaicTilerFactory, add_search_list_route, diff --git a/raster_api/runtime/src/extensions.py b/raster_api/runtime/src/extensions.py index 51271d98..971eba51 100644 --- a/raster_api/runtime/src/extensions.py +++ b/raster_api/runtime/src/extensions.py @@ -11,9 +11,10 @@ from titiler.core.factory import BaseTilerFactory, FactoryExtension DEFAULT_TEMPLATES = Jinja2Templates( - directory="", - loader=jinja2.ChoiceLoader([jinja2.PackageLoader(__package__, "templates")]), -) # type:ignore + env=jinja2.Environment( + loader=jinja2.ChoiceLoader([jinja2.PackageLoader(__package__, "templates")]) + ) +) @dataclass @@ -32,9 +33,9 @@ def stac_viewer( ): """STAC Viewer.""" return self.templates.TemplateResponse( + request, name="stac-viewer.html", context={ - "request": request, "endpoint": request.url.path.replace("/viewer", ""), "collection": item.collection_id, "item": item.id, From cdbaa285eb6dc7d08fbab77a84f2f4870c46c289 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 19 Jul 2024 18:18:46 +0200 Subject: [PATCH 06/22] fix list --- raster_api/runtime/src/app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 6d65ab00..b86b55e3 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -78,8 +78,6 @@ async def lifespan(app: FastAPI): environment_dependency=settings.get_gdal_config, process_dependency=PostProcessParams, router=APIRouter(route_class=LoggerRouteHandler), - # add /list (default to False) - add_mosaic_list=settings.enable_mosaic_search, # add /statistics [POST] (default to False) add_statistics=True, # add /map viewer (default to False) @@ -95,6 +93,7 @@ async def lifespan(app: FastAPI): add_search_register_route( app, + prefix="/mosaic", # any dependency we want to validate # when creating the tilejson/map links tile_dependencies=[ @@ -109,9 +108,10 @@ async def lifespan(app: FastAPI): mosaic.reader_dependency, mosaic.backend_dependency, ], + tags=["Mosaic"], ) # add /list endpoint -add_search_list_route(app) +add_search_list_route(app, prefix="/mosaic", tags=["Mosaic"]) ############################################################################### From fcf3fedda68303efe49b3da9f82dc3226342a6ee Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 19 Jul 2024 18:25:23 +0200 Subject: [PATCH 07/22] fix dependency --- raster_api/runtime/src/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index b86b55e3..cc0a3746 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -23,6 +23,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db +from titiler.pgstac.dependencies import SearchIdParams from titiler.pgstac.extensions import searchInfoExtension from titiler.pgstac.factory import ( MosaicTilerFactory, @@ -73,7 +74,7 @@ async def lifespan(app: FastAPI): ############################################################################### mosaic = MosaicTilerFactory( router_prefix="/mosaic/{search_id}", - path_dependency=ItemPathParams, + path_dependency=SearchIdParams, optional_headers=optional_headers, environment_dependency=settings.get_gdal_config, process_dependency=PostProcessParams, From a5ecbccb9cb873b3dec923f4deadbd3228a17950 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Fri, 19 Jul 2024 18:32:34 +0200 Subject: [PATCH 08/22] fix tests --- .github/workflows/tests/test_raster.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index beba896b..31886f0e 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -22,10 +22,10 @@ def test_mosaic_api(): resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=query) assert resp.headers["content-type"] == "application/json" assert resp.status_code == 200 - assert resp.json()["searchid"] + assert resp.json()["id"] assert resp.json()["links"] - searchid = resp.json()["searchid"] + searchid = resp.json()["id"] resp = httpx.get(f"{raster_endpoint}/mosaic/{searchid}/-85.6358,36.1624/assets") assert resp.status_code == 200 @@ -107,7 +107,7 @@ def test_mosaic_search(): for search in searches: resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=search) assert resp.status_code == 200 - assert resp.json()["searchid"] + assert resp.json()["id"] resp = httpx.get(f"{raster_endpoint}/mosaic/list") assert resp.headers["content-type"] == "application/json" From cdd8986dd8349c64ec511404ed09acae41b6ece3 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Mon, 22 Jul 2024 13:28:33 -0600 Subject: [PATCH 09/22] change route prefix --- raster_api/runtime/src/app.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index cc0a3746..c177ce8f 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -3,10 +3,9 @@ from contextlib import asynccontextmanager from aws_lambda_powertools.metrics import MetricUnit -from src.algorithms import PostProcessParams from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings -from src.dependencies import ColorMapParams, ItemPathParams +from src.dependencies import ItemPathParams from src.extensions import stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -16,7 +15,7 @@ from starlette.requests import Request from starlette_cramjam.middleware import CompressionMiddleware from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers -from titiler.core.factory import MultiBaseTilerFactory, TilerFactory, TMSFactory +from titiler.core.factory import ColorMapFactory, MultiBaseTilerFactory, TilerFactory, TMSFactory from titiler.core.middleware import CacheControlMiddleware from titiler.core.resources.enums import OptionalHeader from titiler.core.resources.responses import JSONResponse @@ -73,11 +72,10 @@ async def lifespan(app: FastAPI): # /mosaic - PgSTAC Mosaic titiler endpoint ############################################################################### mosaic = MosaicTilerFactory( - router_prefix="/mosaic/{search_id}", + router_prefix="/searches/{search_id}", path_dependency=SearchIdParams, optional_headers=optional_headers, environment_dependency=settings.get_gdal_config, - process_dependency=PostProcessParams, router=APIRouter(route_class=LoggerRouteHandler), # add /statistics [POST] (default to False) add_statistics=True, @@ -85,34 +83,25 @@ async def lifespan(app: FastAPI): add_viewer=False, # add /bbox [GET] and /feature [POST] (default to False) add_part=True, - colormap_dependency=ColorMapParams, extensions=[ searchInfoExtension(), ], ) -app.include_router(mosaic.router, prefix="/mosaic/{search_id}", tags=["Mosaic"]) +app.include_router(mosaic.router, prefix="/searches/{search_id}", tags=["Mosaic"]) add_search_register_route( app, - prefix="/mosaic", + prefix="/searches", # any dependency we want to validate # when creating the tilejson/map links tile_dependencies=[ - mosaic.layer_dependency, - mosaic.dataset_dependency, - mosaic.pixel_selection_dependency, mosaic.process_dependency, - mosaic.rescale_dependency, - mosaic.colormap_dependency, - mosaic.render_dependency, - mosaic.pgstac_dependency, - mosaic.reader_dependency, - mosaic.backend_dependency, + mosaic.colormap_dependency ], tags=["Mosaic"], ) # add /list endpoint -add_search_list_route(app, prefix="/mosaic", tags=["Mosaic"]) +add_search_list_route(app, prefix="/searches", tags=["Mosaic"]) ############################################################################### @@ -166,6 +155,11 @@ async def lifespan(app: FastAPI): app.include_router(cog.router, tags=["Cloud Optimized GeoTIFF"], prefix="/cog") +############################################################################### +# Colormaps endpoints +############################################################################### +cmaps = ColorMapFactory() +app.include_router(cmaps.router, tags=["ColorMaps"]) @app.get("/healthz", description="Health Check", tags=["Health Check"]) def ping(): From ddb3a5f48719de148f4fd628e834ce6e664c8704 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Mon, 22 Jul 2024 13:32:20 -0600 Subject: [PATCH 10/22] re-add colormap dependency import --- raster_api/runtime/src/app.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index c177ce8f..ae2e11b1 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -3,9 +3,10 @@ from contextlib import asynccontextmanager from aws_lambda_powertools.metrics import MetricUnit +from src.algorithms import PostProcessParams from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings -from src.dependencies import ItemPathParams +from src.dependencies import ColorMapParams, ItemPathParams from src.extensions import stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -76,6 +77,7 @@ async def lifespan(app: FastAPI): path_dependency=SearchIdParams, optional_headers=optional_headers, environment_dependency=settings.get_gdal_config, + process_dependency=PostProcessParams, router=APIRouter(route_class=LoggerRouteHandler), # add /statistics [POST] (default to False) add_statistics=True, @@ -83,6 +85,7 @@ async def lifespan(app: FastAPI): add_viewer=False, # add /bbox [GET] and /feature [POST] (default to False) add_part=True, + colormap_dependency=ColorMapParams, extensions=[ searchInfoExtension(), ], From d455440eca0a0f03e80fbbf924ce1ddeaa10a2bd Mon Sep 17 00:00:00 2001 From: smohiudd Date: Mon, 22 Jul 2024 13:50:11 -0600 Subject: [PATCH 11/22] format --- raster_api/runtime/src/app.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index ae2e11b1..e3256d40 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -16,7 +16,12 @@ from starlette.requests import Request from starlette_cramjam.middleware import CompressionMiddleware from titiler.core.errors import DEFAULT_STATUS_CODES, add_exception_handlers -from titiler.core.factory import ColorMapFactory, MultiBaseTilerFactory, TilerFactory, TMSFactory +from titiler.core.factory import ( + ColorMapFactory, + MultiBaseTilerFactory, + TilerFactory, + TMSFactory, +) from titiler.core.middleware import CacheControlMiddleware from titiler.core.resources.enums import OptionalHeader from titiler.core.resources.responses import JSONResponse @@ -97,10 +102,7 @@ async def lifespan(app: FastAPI): prefix="/searches", # any dependency we want to validate # when creating the tilejson/map links - tile_dependencies=[ - mosaic.process_dependency, - mosaic.colormap_dependency - ], + tile_dependencies=[mosaic.process_dependency, mosaic.colormap_dependency], tags=["Mosaic"], ) # add /list endpoint @@ -164,6 +166,7 @@ async def lifespan(app: FastAPI): cmaps = ColorMapFactory() app.include_router(cmaps.router, tags=["ColorMaps"]) + @app.get("/healthz", description="Health Check", tags=["Health Check"]) def ping(): """Health check.""" From d4578f12b49b1273f48e5c09703ae51b6a29a052 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Mon, 22 Jul 2024 15:26:14 -0600 Subject: [PATCH 12/22] update tests --- .github/workflows/tests/test_raster.py | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index 31886f0e..b46c9715 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -19,7 +19,7 @@ def test_raster_api(): def test_mosaic_api(): """test mosaic.""" query = {"collections": ["noaa-emergency-response"], "filter-lang": "cql-json"} - resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=query) + resp = httpx.post(f"{raster_endpoint}/searches/register", json=query) assert resp.headers["content-type"] == "application/json" assert resp.status_code == 200 assert resp.json()["id"] @@ -27,13 +27,13 @@ def test_mosaic_api(): searchid = resp.json()["id"] - resp = httpx.get(f"{raster_endpoint}/mosaic/{searchid}/-85.6358,36.1624/assets") + resp = httpx.get(f"{raster_endpoint}/searches/{searchid}/-85.6358,36.1624/assets") assert resp.status_code == 200 assert len(resp.json()) == 1 assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"] assert resp.json()[0]["id"] == "20200307aC0853900w361030" - resp = httpx.get(f"{raster_endpoint}/mosaic/{searchid}/tiles/15/8589/12849/assets") + resp = httpx.get(f"{raster_endpoint}/searches/{searchid}/tiles/15/8589/12849/assets") assert resp.status_code == 200 assert len(resp.json()) == 1 assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"] @@ -41,7 +41,7 @@ def test_mosaic_api(): z, x, y = 15, 8589, 12849 resp = httpx.get( - f"{raster_endpoint}/mosaic/{searchid}/tiles/{z}/{x}/{y}", + f"{raster_endpoint}/searches/{searchid}/tiles/{z}/{x}/{y}", params={"assets": "cog"}, headers={"Accept-Encoding": "br, gzip"}, timeout=10.0, @@ -105,11 +105,11 @@ def test_mosaic_search(): }, ] for search in searches: - resp = httpx.post(f"{raster_endpoint}/mosaic/register", json=search) + resp = httpx.post(f"{raster_endpoint}/searches/register", json=search) assert resp.status_code == 200 assert resp.json()["id"] - resp = httpx.get(f"{raster_endpoint}/mosaic/list") + resp = httpx.get(f"{raster_endpoint}/searches/list") assert resp.headers["content-type"] == "application/json" assert resp.status_code == 200 assert ( @@ -118,16 +118,16 @@ def test_mosaic_search(): assert resp.json()["context"]["returned"] == 10 # default limit is 10 # Make sure all mosaics returned have - for mosaic in resp.json()["searches"]: - assert mosaic["search"]["metadata"]["type"] == "mosaic" + for search in resp.json()["searches"]: + assert search["search"]["metadata"]["type"] == "mosaic" links = resp.json()["links"] assert len(links) == 2 assert links[0]["rel"] == "self" assert links[1]["rel"] == "next" - assert links[1]["href"] == f"{raster_endpoint}/mosaic/list?limit=10&offset=10" + assert links[1]["href"] == f"{raster_endpoint}/searches/list?limit=10&offset=10" - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"limit": 1, "offset": 1}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"limit": 1, "offset": 1}) assert resp.status_code == 200 assert resp.json()["context"]["matched"] > 10 assert resp.json()["context"]["limit"] == 1 @@ -136,33 +136,33 @@ def test_mosaic_search(): links = resp.json()["links"] assert len(links) == 3 assert links[0]["rel"] == "self" - assert links[0]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=1" + assert links[0]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=1" assert links[1]["rel"] == "next" - assert links[1]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=2" + assert links[1]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=2" assert links[2]["rel"] == "prev" - assert links[2]["href"] == f"{raster_endpoint}/mosaic/list?limit=1&offset=0" + assert links[2]["href"] == f"{raster_endpoint}/searches/list?limit=1&offset=0" # Filter on mosaic metadata - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"owner": "vincent"}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"owner": "vincent"}) assert resp.status_code == 200 assert resp.json()["context"]["matched"] == 7 assert resp.json()["context"]["limit"] == 10 assert resp.json()["context"]["returned"] == 7 # sortBy - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "lastused"}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "lastused"}) assert resp.status_code == 200 - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "usecount"}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "usecount"}) assert resp.status_code == 200 - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "-owner"}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "-owner"}) assert resp.status_code == 200 assert ( "owner" not in resp.json()["searches"][0]["search"]["metadata"] ) # some mosaic don't have owners - resp = httpx.get(f"{raster_endpoint}/mosaic/list", params={"sortby": "owner"}) + resp = httpx.get(f"{raster_endpoint}/searches/list", params={"sortby": "owner"}) assert resp.status_code == 200 assert "owner" in resp.json()["searches"][0]["search"]["metadata"] From 139182e2118a1ca320bd587d4679abcda9a8eca7 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Mon, 22 Jul 2024 15:27:57 -0600 Subject: [PATCH 13/22] format --- .github/workflows/tests/test_raster.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index b46c9715..0c4b0777 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -33,7 +33,9 @@ def test_mosaic_api(): assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"] assert resp.json()[0]["id"] == "20200307aC0853900w361030" - resp = httpx.get(f"{raster_endpoint}/searches/{searchid}/tiles/15/8589/12849/assets") + resp = httpx.get( + f"{raster_endpoint}/searches/{searchid}/tiles/15/8589/12849/assets" + ) assert resp.status_code == 200 assert len(resp.json()) == 1 assert list(resp.json()[0]) == ["id", "bbox", "assets", "collection"] @@ -127,7 +129,9 @@ def test_mosaic_search(): assert links[1]["rel"] == "next" assert links[1]["href"] == f"{raster_endpoint}/searches/list?limit=10&offset=10" - resp = httpx.get(f"{raster_endpoint}/searches/list", params={"limit": 1, "offset": 1}) + resp = httpx.get( + f"{raster_endpoint}/searches/list", params={"limit": 1, "offset": 1} + ) assert resp.status_code == 200 assert resp.json()["context"]["matched"] > 10 assert resp.json()["context"]["limit"] == 1 From 2db7ac6550079b445e45ec14f2c846b27ef7567a Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 09:08:34 -0600 Subject: [PATCH 14/22] add collection endpoint --- raster_api/runtime/src/app.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index e3256d40..8a719d67 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -28,7 +28,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db -from titiler.pgstac.dependencies import SearchIdParams +from titiler.pgstac.dependencies import CollectionIdParams, SearchIdParams from titiler.pgstac.extensions import searchInfoExtension from titiler.pgstac.factory import ( MosaicTilerFactory, @@ -75,7 +75,7 @@ async def lifespan(app: FastAPI): add_exception_handlers(app, MOSAIC_STATUS_CODES) ############################################################################### -# /mosaic - PgSTAC Mosaic titiler endpoint +# /searches - PgSTAC Mosaic titiler endpoint ############################################################################### mosaic = MosaicTilerFactory( router_prefix="/searches/{search_id}", @@ -108,6 +108,24 @@ async def lifespan(app: FastAPI): # add /list endpoint add_search_list_route(app, prefix="/searches", tags=["Mosaic"]) +############################################################################### +# STAC COLLECTION Endpoints +############################################################################### +collection = MosaicTilerFactory( + path_dependency=CollectionIdParams, + optional_headers=optional_headers, + router_prefix="/collections/{collection_id}", + add_statistics=True, + add_viewer=True, + add_part=True, + extensions=[ + searchInfoExtension(), + ], +) +app.include_router( + collection.router, tags=["STAC Collection"], prefix="/collections/{collection_id}" +) + ############################################################################### # /stac - Custom STAC titiler endpoint From 89f2d0fa0ea964dfc2401b090a32442c2e17d8f9 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 09:33:55 -0600 Subject: [PATCH 15/22] change items endpoint --- raster_api/runtime/src/app.py | 28 ++++++++++++++++++-------- raster_api/runtime/src/dependencies.py | 21 ------------------- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 8a719d67..500f39ca 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -6,7 +6,7 @@ from src.algorithms import PostProcessParams from src.alternate_reader import PgSTACReaderAlt from src.config import ApiSettings -from src.dependencies import ColorMapParams, ItemPathParams +from src.dependencies import ColorMapParams from src.extensions import stacViewerExtension from src.monitoring import LoggerRouteHandler, logger, metrics, tracer from src.version import __version__ as veda_raster_version @@ -28,7 +28,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db -from titiler.pgstac.dependencies import CollectionIdParams, SearchIdParams +from titiler.pgstac.dependencies import CollectionIdParams, ItemPathParams, SearchIdParams from titiler.pgstac.extensions import searchInfoExtension from titiler.pgstac.factory import ( MosaicTilerFactory, @@ -77,7 +77,7 @@ async def lifespan(app: FastAPI): ############################################################################### # /searches - PgSTAC Mosaic titiler endpoint ############################################################################### -mosaic = MosaicTilerFactory( +searches = MosaicTilerFactory( router_prefix="/searches/{search_id}", path_dependency=SearchIdParams, optional_headers=optional_headers, @@ -95,18 +95,30 @@ async def lifespan(app: FastAPI): searchInfoExtension(), ], ) -app.include_router(mosaic.router, prefix="/searches/{search_id}", tags=["Mosaic"]) +app.include_router(searches.router, prefix="/searches/{search_id}", tags=["Mosaic"]) add_search_register_route( app, prefix="/searches", # any dependency we want to validate # when creating the tilejson/map links - tile_dependencies=[mosaic.process_dependency, mosaic.colormap_dependency], + tile_dependencies=[ + searches.layer_dependency, + searches.dataset_dependency, + searches.pixel_selection_dependency, + searches.process_dependency, + searches.rescale_dependency, + searches.colormap_dependency, + searches.render_dependency, + searches.pgstac_dependency, + searches.reader_dependency, + searches.backend_dependency, + ], tags=["Mosaic"], ) # add /list endpoint -add_search_list_route(app, prefix="/searches", tags=["Mosaic"]) +if settings.enable_mosaic_search: + add_search_list_route(app, prefix="/searches", tags=["Mosaic"]) ############################################################################### # STAC COLLECTION Endpoints @@ -134,7 +146,7 @@ async def lifespan(app: FastAPI): reader=PgSTACReader, path_dependency=ItemPathParams, optional_headers=optional_headers, - router_prefix="/stac", + router_prefix="/collections/{collection_id}/items/{item_id}", environment_dependency=settings.get_gdal_config, router=APIRouter(route_class=LoggerRouteHandler), extensions=[ @@ -142,7 +154,7 @@ async def lifespan(app: FastAPI): ], colormap_dependency=ColorMapParams, ) -app.include_router(stac.router, tags=["Items"], prefix="/stac") +app.include_router(stac.router, tags=["Items"], prefix="/collections/{collection_id}/items/{item_id}") ############################################################################### # /stac-alt - Custom STAC titiler endpoint for alternate asset locations diff --git a/raster_api/runtime/src/dependencies.py b/raster_api/runtime/src/dependencies.py index c41ef552..cee0a08b 100644 --- a/raster_api/runtime/src/dependencies.py +++ b/raster_api/runtime/src/dependencies.py @@ -1,13 +1,8 @@ """veda.raster.dependencies.""" -import pystac from rio_tiler.colormap import cmap as default_cmap -from typing_extensions import Annotated -from fastapi import Query -from starlette.requests import Request from titiler.core.dependencies import create_colormap_dependency -from titiler.pgstac.dependencies import get_stac_item try: from importlib.resources import files as resources_files # type: ignore @@ -15,22 +10,6 @@ # Try backported to PY<39 `importlib_resources`. from importlib_resources import files as resources_files # type: ignore - -def ItemPathParams( - request: Request, - collection: Annotated[ - str, - Query(description="STAC Collection ID"), - ], - item: Annotated[ - str, - Query(description="STAC Item ID"), - ], -) -> pystac.Item: - """STAC Item dependency.""" - return get_stac_item(request.app.state.dbpool, collection, item) - - VEDA_CMAPS_FILES = { f.stem: str(f) for f in (resources_files(__package__) / "cmap_data").glob("*.npy") # type: ignore } From 6fecd6cc0061c9f0efdfe10fa66c02d3f38a3fcb Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 09:37:05 -0600 Subject: [PATCH 16/22] update alt endpoint --- raster_api/runtime/src/app.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 500f39ca..c7d6f429 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -28,7 +28,7 @@ from titiler.extensions import cogValidateExtension, cogViewerExtension from titiler.mosaic.errors import MOSAIC_STATUS_CODES from titiler.pgstac.db import close_db_connection, connect_to_db -from titiler.pgstac.dependencies import CollectionIdParams, ItemPathParams, SearchIdParams +from titiler.pgstac.dependencies import CollectionIdParams, ItemIdParams, SearchIdParams from titiler.pgstac.extensions import searchInfoExtension from titiler.pgstac.factory import ( MosaicTilerFactory, @@ -140,11 +140,11 @@ async def lifespan(app: FastAPI): ############################################################################### -# /stac - Custom STAC titiler endpoint +# /collections/{collection_id}/items/{item_id} - Custom STAC titiler endpoint ############################################################################### stac = MultiBaseTilerFactory( reader=PgSTACReader, - path_dependency=ItemPathParams, + path_dependency=ItemIdParams, optional_headers=optional_headers, router_prefix="/collections/{collection_id}/items/{item_id}", environment_dependency=settings.get_gdal_config, @@ -157,13 +157,13 @@ async def lifespan(app: FastAPI): app.include_router(stac.router, tags=["Items"], prefix="/collections/{collection_id}/items/{item_id}") ############################################################################### -# /stac-alt - Custom STAC titiler endpoint for alternate asset locations +# /alt/collections/{collection_id}/items/{item_id} - Custom STAC titiler endpoint for alternate asset locations ############################################################################### stac_alt = MultiBaseTilerFactory( reader=PgSTACReaderAlt, - path_dependency=ItemPathParams, + path_dependency=ItemIdParams, optional_headers=optional_headers, - router_prefix="/stac-alt", + router_prefix="/alt/collections/{collection_id}/items/{item_id}", environment_dependency=settings.get_gdal_config, router=APIRouter(route_class=LoggerRouteHandler), extensions=[ @@ -171,7 +171,7 @@ async def lifespan(app: FastAPI): ], colormap_dependency=ColorMapParams, ) -app.include_router(stac_alt.router, tags=["Items"], prefix="/stac-alt") +app.include_router(stac_alt.router, tags=["Items"], prefix="/alt/collections/{collection_id}/items/{item_id}") ############################################################################### # /cog - External Cloud Optimized GeoTIFF endpoints From 5ba94f3def760226fa9f1a30c4f689b37a8f90ae Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 13:36:15 -0600 Subject: [PATCH 17/22] add endpoint tags --- raster_api/runtime/src/app.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index c7d6f429..6ffda708 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -97,6 +97,7 @@ async def lifespan(app: FastAPI): ) app.include_router(searches.router, prefix="/searches/{search_id}", tags=["Mosaic"]) +# add /register endpoint add_search_register_route( app, prefix="/searches", @@ -114,7 +115,6 @@ async def lifespan(app: FastAPI): searches.reader_dependency, searches.backend_dependency, ], - tags=["Mosaic"], ) # add /list endpoint if settings.enable_mosaic_search: @@ -154,7 +154,11 @@ async def lifespan(app: FastAPI): ], colormap_dependency=ColorMapParams, ) -app.include_router(stac.router, tags=["Items"], prefix="/collections/{collection_id}/items/{item_id}") +app.include_router( + stac.router, + tags=["STAC Item"], + prefix="/collections/{collection_id}/items/{item_id}", +) ############################################################################### # /alt/collections/{collection_id}/items/{item_id} - Custom STAC titiler endpoint for alternate asset locations @@ -171,7 +175,11 @@ async def lifespan(app: FastAPI): ], colormap_dependency=ColorMapParams, ) -app.include_router(stac_alt.router, tags=["Items"], prefix="/alt/collections/{collection_id}/items/{item_id}") +app.include_router( + stac_alt.router, + tags=["Alt STAC Item"], + prefix="/alt/collections/{collection_id}/items/{item_id}", +) ############################################################################### # /cog - External Cloud Optimized GeoTIFF endpoints From dd96a7f212f5c392a3ad415a2338514467e73647 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 14:10:25 -0600 Subject: [PATCH 18/22] fix tests --- .github/workflows/tests/test_raster.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index 0c4b0777..187d3e80 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -173,22 +173,18 @@ def test_mosaic_search(): def test_item(): """test stac endpoints.""" + collection_id="noaa-emergency-response" + item_id="20200307aC0853300w361200" resp = httpx.get( - f"{raster_endpoint}/stac/assets", - params={ - "collection": "noaa-emergency-response", - "item": "20200307aC0853300w361200", - }, + f"{raster_endpoint}/collections/{collection_id}/items/{item_id}/assets" ) assert resp.status_code == 200 assert resp.headers["content-type"] == "application/json" assert resp.json() == ["cog"] resp = httpx.get( - f"{raster_endpoint}/stac/tilejson.json", + f"{raster_endpoint}/collections/{collection_id}/items/{item_id}/tilejson.json", params={ - "collection": "noaa-emergency-response", - "item": "20200307aC0853300w361200", "assets": "cog", }, ) From 7a6848e0d280cf996407862a99a2b02ba4a902a7 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 14:13:33 -0600 Subject: [PATCH 19/22] format --- .github/workflows/tests/test_raster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index 187d3e80..4388e171 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -173,8 +173,8 @@ def test_mosaic_search(): def test_item(): """test stac endpoints.""" - collection_id="noaa-emergency-response" - item_id="20200307aC0853300w361200" + collection_id = "noaa-emergency-response" + item_id = "20200307aC0853300w361200" resp = httpx.get( f"{raster_endpoint}/collections/{collection_id}/items/{item_id}/assets" ) From ab06ebbd7d0c84ba64269603d960d800a0aa3a92 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 17:02:38 -0600 Subject: [PATCH 20/22] update tags --- .github/workflows/tests/test_raster.py | 2 +- raster_api/runtime/src/app.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index 4388e171..bf080b9d 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -183,7 +183,7 @@ def test_item(): assert resp.json() == ["cog"] resp = httpx.get( - f"{raster_endpoint}/collections/{collection_id}/items/{item_id}/tilejson.json", + f"{raster_endpoint}/collections/{collection_id}/items/{item_id}/WebMercatorQuad/tilejson.json", params={ "assets": "cog", }, diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index 6ffda708..c49890af 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -95,7 +95,7 @@ async def lifespan(app: FastAPI): searchInfoExtension(), ], ) -app.include_router(searches.router, prefix="/searches/{search_id}", tags=["Mosaic"]) +app.include_router(searches.router, prefix="/searches/{search_id}", tags=["STAC Search"]) # add /register endpoint add_search_register_route( @@ -115,10 +115,11 @@ async def lifespan(app: FastAPI): searches.reader_dependency, searches.backend_dependency, ], + tags=["STAC Search"] ) # add /list endpoint if settings.enable_mosaic_search: - add_search_list_route(app, prefix="/searches", tags=["Mosaic"]) + add_search_list_route(app, prefix="/searches", tags=["STAC Search"]) ############################################################################### # STAC COLLECTION Endpoints From 4652db8feb4ccfdc94c07eadc9a2df8baa75bb9d Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 17:25:51 -0600 Subject: [PATCH 21/22] format, tag change --- raster_api/runtime/src/app.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index c49890af..c8bd57a7 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -75,7 +75,7 @@ async def lifespan(app: FastAPI): add_exception_handlers(app, MOSAIC_STATUS_CODES) ############################################################################### -# /searches - PgSTAC Mosaic titiler endpoint +# /searches - STAC Search endpoint ############################################################################### searches = MosaicTilerFactory( router_prefix="/searches/{search_id}", @@ -95,7 +95,9 @@ async def lifespan(app: FastAPI): searchInfoExtension(), ], ) -app.include_router(searches.router, prefix="/searches/{search_id}", tags=["STAC Search"]) +app.include_router( + searches.router, prefix="/searches/{search_id}", tags=["STAC Search"] +) # add /register endpoint add_search_register_route( @@ -115,7 +117,7 @@ async def lifespan(app: FastAPI): searches.reader_dependency, searches.backend_dependency, ], - tags=["STAC Search"] + tags=["STAC Search"], ) # add /list endpoint if settings.enable_mosaic_search: @@ -178,7 +180,7 @@ async def lifespan(app: FastAPI): ) app.include_router( stac_alt.router, - tags=["Alt STAC Item"], + tags=["Alt Href STAC Item"], prefix="/alt/collections/{collection_id}/items/{item_id}", ) From 4e109232fb8a078251990507c2e07105f57dbc88 Mon Sep 17 00:00:00 2001 From: smohiudd Date: Wed, 24 Jul 2024 17:47:27 -0600 Subject: [PATCH 22/22] not include alt schema --- .github/workflows/tests/test_raster.py | 2 -- raster_api/runtime/src/app.py | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests/test_raster.py b/.github/workflows/tests/test_raster.py index bf080b9d..e21731c0 100644 --- a/.github/workflows/tests/test_raster.py +++ b/.github/workflows/tests/test_raster.py @@ -192,6 +192,4 @@ def test_item(): assert resp.headers["content-type"] == "application/json" assert resp.json()["tilejson"] assert "assets=cog" in resp.json()["tiles"][0] - assert "item=20200307aC0853300w361200" in resp.json()["tiles"][0] - assert "collection=noaa-emergency-response" in resp.json()["tiles"][0] assert resp.json()["bounds"] == [-85.5501, 36.1749, -85.5249, 36.2001] diff --git a/raster_api/runtime/src/app.py b/raster_api/runtime/src/app.py index c8bd57a7..5e0bdc5e 100644 --- a/raster_api/runtime/src/app.py +++ b/raster_api/runtime/src/app.py @@ -182,6 +182,7 @@ async def lifespan(app: FastAPI): stac_alt.router, tags=["Alt Href STAC Item"], prefix="/alt/collections/{collection_id}/items/{item_id}", + include_in_schema=False, ) ###############################################################################