-
Notifications
You must be signed in to change notification settings - Fork 117
Browseable and Children features from 1.0.0-beta5 #336
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
Closed
moradology
wants to merge
21
commits into
stac-utils:master
from
moradology:feature/children-1.0.0-beta.5
Closed
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
f939811
Init work towards children endpoint
moradology 8a1339c
Implement alternative backing for browsable features
moradology 122ac4b
Update links and support /children
moradology 546b6f0
Add example of nested catalog
moradology ab06b8b
Remove printlns
moradology e986169
Simplify url construction
moradology 932dc4d
Add conformance classes
moradology d943c90
Spell browseable correctly
moradology f4c5620
Add full page for catalogs to support API functionality
moradology dadce7d
Add support for sub-catalog behaviors
moradology c1f6b3c
Break clients out for more organization and smaller files
moradology 316661c
Add todos for pgstac
moradology 391a732
Add /catalogs/{catalog}/children endpoint
moradology 7c049f5
Bump conformance classes to rc1
moradology dd13bff
Fix import after rebase
moradology 8baf324
Set mimetype on search link to geojson
moradology 591fc27
Remove duplicate introduced via rebase
moradology b908269
Bump version to rc1
moradology 242e1fe
Respond to review
moradology 34af872
Avoid error when no hierarchy file is specified
moradology 42f5e28
Use new relations from stac-pydantic 2.0.3
moradology File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
from fastapi.openapi.utils import get_openapi | ||
from fastapi.params import Depends | ||
from pydantic import BaseModel | ||
from stac_pydantic import Collection, Item, ItemCollection | ||
from stac_pydantic import Catalog, Collection, Item, ItemCollection | ||
from stac_pydantic.api import ConformanceClasses, LandingPage | ||
from stac_pydantic.api.collections import Collections | ||
from stac_pydantic.version import STAC_VERSION | ||
|
@@ -16,6 +16,7 @@ | |
from stac_fastapi.api.errors import DEFAULT_STATUS_CODES, add_exception_handlers | ||
from stac_fastapi.api.models import ( | ||
APIRequest, | ||
CatalogUri, | ||
CollectionUri, | ||
EmptyRequest, | ||
GeoJSONResponse, | ||
|
@@ -33,10 +34,12 @@ | |
|
||
# TODO: make this module not depend on `stac_fastapi.extensions` | ||
from stac_fastapi.extensions.core import FieldsExtension, TokenPaginationExtension | ||
from stac_fastapi.types.clients.async_core import AsyncBaseCoreClient | ||
from stac_fastapi.types.clients.sync_core import BaseCoreClient | ||
from stac_fastapi.types.config import ApiSettings, Settings | ||
from stac_fastapi.types.core import AsyncBaseCoreClient, BaseCoreClient | ||
from stac_fastapi.types.extension import ApiExtension | ||
from stac_fastapi.types.search import BaseSearchGetRequest, BaseSearchPostRequest | ||
from stac_fastapi.types.stac import Children | ||
|
||
|
||
@attr.s | ||
|
@@ -83,9 +86,15 @@ class StacApi: | |
api_version: str = attr.ib(default="0.1") | ||
stac_version: str = attr.ib(default=STAC_VERSION) | ||
description: str = attr.ib(default="stac-fastapi") | ||
search_get_request_base_model: Type[BaseSearchGetRequest] = attr.ib( | ||
default=BaseSearchGetRequest | ||
) | ||
search_get_request_model: Type[BaseSearchGetRequest] = attr.ib( | ||
default=BaseSearchGetRequest | ||
) | ||
search_post_request_base_model: Type[BaseSearchPostRequest] = attr.ib( | ||
default=BaseSearchPostRequest | ||
) | ||
search_post_request_model: Type[BaseSearchPostRequest] = attr.ib( | ||
default=BaseSearchPostRequest | ||
) | ||
|
@@ -266,6 +275,44 @@ def register_get_collection(self): | |
), | ||
) | ||
|
||
def register_get_root_children(self): | ||
"""Register get collection children endpoint (GET /children). | ||
|
||
Returns: | ||
None | ||
""" | ||
self.router.add_api_route( | ||
name="Get Root Children", | ||
path="/children", | ||
response_model=Children if self.settings.enable_response_models else None, | ||
response_class=self.response_class, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.get_root_children, EmptyRequest, self.response_class | ||
), | ||
) | ||
|
||
def register_get_catalog_children(self): | ||
"""Register get collection children endpoint (GET /collection/{collection_id}/children). | ||
|
||
Returns: | ||
None | ||
""" | ||
self.router.add_api_route( | ||
name="Get Root Children", | ||
path="/catalogs/{catalog_path:path}/children", | ||
response_model=Children if self.settings.enable_response_models else None, | ||
response_class=self.response_class, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.get_catalog_children, CatalogUri, self.response_class | ||
), | ||
) | ||
|
||
def register_get_item_collection(self): | ||
"""Register get item collection endpoint (GET /collection/{collection_id}/items). | ||
|
||
|
@@ -293,6 +340,119 @@ def register_get_item_collection(self): | |
), | ||
) | ||
|
||
def register_catalog_conformance_classes(self): | ||
"""Register catalog conformance class endpoint (GET /catalogs/{catalog_path}/conformance). | ||
|
||
Returns: | ||
None | ||
""" | ||
self.router.add_api_route( | ||
name="Conformance Classes", | ||
path="/catalogs/{catalog_path:path}/conformance", | ||
response_model=ConformanceClasses | ||
if self.settings.enable_response_models | ||
else None, | ||
response_class=self.response_class, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.conformance, EmptyRequest, self.response_class | ||
), | ||
) | ||
|
||
def register_post_catalog_search(self): | ||
"""Register search endpoint (POST /search). | ||
|
||
Returns: | ||
None | ||
""" | ||
fields_ext = self.get_extension(FieldsExtension) | ||
self.router.add_api_route( | ||
name="Search", | ||
path="/catalogs/{catalog_path:path}/search", | ||
response_model=(ItemCollection if not fields_ext else None) | ||
if self.settings.enable_response_models | ||
else None, | ||
response_class=GeoJSONResponse, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["POST"], | ||
endpoint=self._create_endpoint( | ||
self.client.post_catalog_search, | ||
self.search_post_request_model, | ||
GeoJSONResponse, | ||
), | ||
) | ||
|
||
def register_get_catalog_search(self): | ||
"""Register catalog search endpoint (GET /catalogs/{catalog_path}/search). | ||
|
||
Returns: | ||
None | ||
""" | ||
fields_ext = self.get_extension(FieldsExtension) | ||
request_model = create_request_model( | ||
"GetSearchWithCatalogUri", | ||
base_model=self.search_get_request_base_model, | ||
extensions=self.extensions, | ||
mixins=[CatalogUri], | ||
) | ||
self.router.add_api_route( | ||
name="Catalog Search", | ||
path="/catalogs/{catalog_path:path}/search", | ||
response_model=(ItemCollection if not fields_ext else None) | ||
if self.settings.enable_response_models | ||
else None, | ||
response_class=GeoJSONResponse, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.get_catalog_search, request_model, GeoJSONResponse | ||
), | ||
) | ||
|
||
def register_get_catalog_collections(self): | ||
"""Register get collections endpoint (GET /collections). | ||
|
||
Returns: | ||
None | ||
""" | ||
self.router.add_api_route( | ||
name="Get Collections", | ||
path="/catalogs/{catalog_path:path}/collections", | ||
response_model=Collections | ||
if self.settings.enable_response_models | ||
else None, | ||
response_class=self.response_class, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.get_catalog_collections, CatalogUri, self.response_class | ||
), | ||
) | ||
|
||
def register_get_catalog(self): | ||
"""Register get collection endpoint (GET /catalog/{catalog_path}). | ||
|
||
Returns: | ||
None | ||
""" | ||
self.router.add_api_route( | ||
name="Get Catalog", | ||
path="/catalogs/{catalog_path:path}", | ||
response_model=Catalog if self.settings.enable_response_models else None, | ||
response_class=self.response_class, | ||
response_model_exclude_unset=True, | ||
response_model_exclude_none=True, | ||
methods=["GET"], | ||
endpoint=self._create_endpoint( | ||
self.client.get_catalog, CatalogUri, self.response_class | ||
), | ||
) | ||
|
||
def register_core(self): | ||
"""Register core STAC endpoints. | ||
|
||
|
@@ -319,6 +479,16 @@ def register_core(self): | |
self.register_get_collection() | ||
self.register_get_item_collection() | ||
|
||
# Browseable endpoints | ||
self.register_catalog_conformance_classes() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to hide these behind some sort of flag (disabled by default) for two reasons:
|
||
self.register_post_catalog_search() | ||
self.register_get_catalog_search() | ||
self.register_get_catalog_collections() | ||
if self.settings.browseable_hierarchy_definition is not None: | ||
self.register_get_root_children() | ||
self.register_get_catalog_children() | ||
self.register_get_catalog() | ||
|
||
def customize_openapi(self) -> Optional[Dict[str, Any]]: | ||
"""Customize openapi schema.""" | ||
if self.app.openapi_schema: | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whats the difference between this and
search_get_request_model
? Same comment for post models.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a potentially ugly and maybe a point where you could provide some counsel. Basically, the need to supply a catalog URI parameter changes the constructed search model so what I'm doing here is passing in the base
search_get_request_base_model
because it might possibly differ from the fully constructedsearch_get_request_model
used by standard searches. Perhaps the answer is to just construct both of these inside ofcore.py
. Let me know what you think.