Skip to content

Commit 191b75f

Browse files
committed
Add support for sub-catalog behaviors
1 parent db339c7 commit 191b75f

File tree

4 files changed

+452
-64
lines changed

4 files changed

+452
-64
lines changed

stac_fastapi/api/stac_fastapi/api/app.py

Lines changed: 125 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ class StacApi:
8181
api_version: str = attr.ib(default="0.1")
8282
stac_version: str = attr.ib(default=STAC_VERSION)
8383
description: str = attr.ib(default="stac-fastapi")
84+
search_get_request_base_model: Type[BaseSearchGetRequest] = attr.ib(
85+
default=BaseSearchGetRequest
86+
)
8487
search_get_request_model: Type[BaseSearchGetRequest] = attr.ib(
8588
default=BaseSearchGetRequest
8689
)
90+
search_post_request_base_model: Type[BaseSearchPostRequest] = attr.ib(
91+
default=BaseSearchPostRequest
92+
)
8793
search_post_request_model: Type[BaseSearchPostRequest] = attr.ib(
8894
default=BaseSearchPostRequest
8995
)
@@ -263,25 +269,6 @@ def register_get_collection(self):
263269
),
264270
)
265271

266-
def register_get_catalog(self):
267-
"""Register get collection endpoint (GET /catalog/{catalog_path}).
268-
269-
Returns:
270-
None
271-
"""
272-
self.router.add_api_route(
273-
name="Get Catalog",
274-
path="/catalogs/{catalog_path:path}",
275-
response_model=Catalog if self.settings.enable_response_models else None,
276-
response_class=self.response_class,
277-
response_model_exclude_unset=True,
278-
response_model_exclude_none=True,
279-
methods=["GET"],
280-
endpoint=self._create_endpoint(
281-
self.client.get_catalog, CatalogUri, self.response_class
282-
),
283-
)
284-
285272
def register_get_root_children(self):
286273
"""Register get collection children endpoint (GET /collection/{collection_id}/children).
287274
@@ -328,6 +315,119 @@ def register_get_item_collection(self):
328315
),
329316
)
330317

318+
def register_catalog_conformance_classes(self):
319+
"""Register catalog conformance class endpoint (GET /catalogs/{catalog_path}/conformance).
320+
321+
Returns:
322+
None
323+
"""
324+
self.router.add_api_route(
325+
name="Conformance Classes",
326+
path="/catalogs/{catalog_path:path}/conformance",
327+
response_model=ConformanceClasses
328+
if self.settings.enable_response_models
329+
else None,
330+
response_class=self.response_class,
331+
response_model_exclude_unset=True,
332+
response_model_exclude_none=True,
333+
methods=["GET"],
334+
endpoint=self._create_endpoint(
335+
self.client.conformance, EmptyRequest, self.response_class
336+
),
337+
)
338+
339+
def register_post_catalog_search(self):
340+
"""Register search endpoint (POST /search).
341+
342+
Returns:
343+
None
344+
"""
345+
fields_ext = self.get_extension(FieldsExtension)
346+
self.router.add_api_route(
347+
name="Search",
348+
path="/catalogs/{catalog_path:path}/search",
349+
response_model=(ItemCollection if not fields_ext else None)
350+
if self.settings.enable_response_models
351+
else None,
352+
response_class=GeoJSONResponse,
353+
response_model_exclude_unset=True,
354+
response_model_exclude_none=True,
355+
methods=["POST"],
356+
endpoint=self._create_endpoint(
357+
self.client.post_catalog_search,
358+
self.search_post_request_model,
359+
GeoJSONResponse,
360+
),
361+
)
362+
363+
def register_get_catalog_search(self):
364+
"""Register catalog search endpoint (GET /catalogs/{catalog_path}/search).
365+
366+
Returns:
367+
None
368+
"""
369+
fields_ext = self.get_extension(FieldsExtension)
370+
request_model = create_request_model(
371+
"GetSearchWithCatalogUri",
372+
base_model=self.search_get_request_base_model,
373+
extensions=self.extensions,
374+
mixins=[CatalogUri],
375+
)
376+
self.router.add_api_route(
377+
name="Catalog Search",
378+
path="/catalogs/{catalog_path:path}/search",
379+
response_model=(ItemCollection if not fields_ext else None)
380+
if self.settings.enable_response_models
381+
else None,
382+
response_class=GeoJSONResponse,
383+
response_model_exclude_unset=True,
384+
response_model_exclude_none=True,
385+
methods=["GET"],
386+
endpoint=self._create_endpoint(
387+
self.client.get_catalog_search, request_model, GeoJSONResponse
388+
),
389+
)
390+
391+
def register_get_catalog_collections(self):
392+
"""Register get collections endpoint (GET /collections).
393+
394+
Returns:
395+
None
396+
"""
397+
self.router.add_api_route(
398+
name="Get Collections",
399+
path="/catalogs/{catalog_path:path}/collections",
400+
response_model=Collections
401+
if self.settings.enable_response_models
402+
else None,
403+
response_class=self.response_class,
404+
response_model_exclude_unset=True,
405+
response_model_exclude_none=True,
406+
methods=["GET"],
407+
endpoint=self._create_endpoint(
408+
self.client.get_catalog_collections, CatalogUri, self.response_class
409+
),
410+
)
411+
412+
def register_get_catalog(self):
413+
"""Register get collection endpoint (GET /catalog/{catalog_path}).
414+
415+
Returns:
416+
None
417+
"""
418+
self.router.add_api_route(
419+
name="Get Catalog",
420+
path="/catalogs/{catalog_path:path}",
421+
response_model=Catalog if self.settings.enable_response_models else None,
422+
response_class=self.response_class,
423+
response_model_exclude_unset=True,
424+
response_model_exclude_none=True,
425+
methods=["GET"],
426+
endpoint=self._create_endpoint(
427+
self.client.get_catalog, CatalogUri, self.response_class
428+
),
429+
)
430+
331431
def register_core(self):
332432
"""Register core STAC endpoints.
333433
@@ -352,9 +452,14 @@ def register_core(self):
352452
self.register_get_search()
353453
self.register_get_collections()
354454
self.register_get_collection()
355-
self.register_get_catalog()
356455
self.register_get_item_collection()
357456

457+
# Browseable endpoints
458+
self.register_catalog_conformance_classes()
459+
self.register_post_catalog_search()
460+
self.register_get_catalog_search()
461+
self.register_get_catalog_collections()
462+
self.register_get_catalog()
358463
if self.settings.browseable_hierarchy_definition is not None:
359464
self.register_get_root_children()
360465

stac_fastapi/api/stac_fastapi/api/models.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""api request/response models."""
22

33
import importlib.util
4-
from typing import Optional, Type, Union
4+
from typing import List, Optional, Type, Union
55

66
import attr
77
from fastapi import Body, Path
@@ -19,8 +19,8 @@
1919
def create_request_model(
2020
model_name="SearchGetRequest",
2121
base_model: Union[Type[BaseModel], APIRequest] = BaseSearchGetRequest,
22-
extensions: Optional[ApiExtension] = None,
23-
mixins: Optional[Union[BaseModel, APIRequest]] = None,
22+
extensions: Optional[List[ApiExtension]] = None,
23+
mixins: Optional[List[Union[BaseModel, APIRequest]]] = None,
2424
request_type: Optional[str] = "GET",
2525
) -> Union[Type[BaseModel], APIRequest]:
2626
"""Create a pydantic model for validating request bodies."""
@@ -74,25 +74,27 @@ def create_request_model(
7474

7575

7676
def create_get_request_model(
77-
extensions, base_model: BaseSearchGetRequest = BaseSearchGetRequest
77+
extensions, base_model: BaseSearchGetRequest = BaseSearchGetRequest, mixins=None
7878
):
7979
"""Wrap create_request_model to create the GET request model."""
8080
return create_request_model(
8181
"SearchGetRequest",
8282
base_model=base_model,
8383
extensions=extensions,
84+
mixins=mixins,
8485
request_type="GET",
8586
)
8687

8788

8889
def create_post_request_model(
89-
extensions, base_model: BaseSearchPostRequest = BaseSearchPostRequest
90+
extensions, base_model: BaseSearchPostRequest = BaseSearchPostRequest, mixins=None
9091
):
9192
"""Wrap create_request_model to create the POST request model."""
9293
return create_request_model(
9394
"SearchPostRequest",
9495
base_model=base_model,
9596
extensions=extensions,
97+
mixins=mixins,
9698
request_type="POST",
9799
)
98100

stac_fastapi/pgstac/stac_fastapi/pgstac/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
),
4848
response_class=ORJSONResponse,
4949
search_get_request_model=create_get_request_model(extensions),
50+
search_post_request_base_model=PgstacSearch,
5051
search_post_request_model=post_request_model,
5152
)
5253
app = api.app

0 commit comments

Comments
 (0)