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

re-formatting collections endpoint to match spec. #232

Merged
merged 8 commits into from
Aug 18, 2021
28 changes: 25 additions & 3 deletions stac_fastapi/pgstac/stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
import re
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from urllib.parse import urljoin

import attr
import orjson
from buildpg import render
from fastapi import HTTPException
from pydantic import ValidationError
from stac_pydantic.links import Relations
from stac_pydantic.shared import MimeTypes
from starlette.requests import Request

from stac_fastapi.pgstac.models.links import CollectionLinks, ItemLinks, PagingLinks
from stac_fastapi.pgstac.types.search import PgstacSearch
from stac_fastapi.types.core import AsyncBaseCoreClient
from stac_fastapi.types.errors import NotFoundError
from stac_fastapi.types.stac import Collection, Item, ItemCollection
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection

NumType = Union[float, int]

Expand All @@ -23,9 +26,10 @@
class CoreCrudClient(AsyncBaseCoreClient):
"""Client for core endpoints defined by stac."""

async def all_collections(self, **kwargs) -> List[Collection]:
async def all_collections(self, **kwargs) -> Collections:
"""Read all collections from the database."""
request: Request = kwargs["request"]
base_url = str(request.base_url)
pool = request.app.state.readpool

async with pool.acquire() as conn:
Expand All @@ -42,7 +46,25 @@ async def all_collections(self, **kwargs) -> List[Collection]:
collection_id=coll["id"], request=request
).get_links()
linked_collections.append(coll)
return linked_collections
links = [
{
"rel": Relations.root.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.parent.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.self.value,
"type": MimeTypes.json,
"href": urljoin(base_url, "collections"),
},
]
collection_list = Collections(collections=collections or [], links=links)
return collection_list

async def get_collection(self, id: str, **kwargs) -> Collection:
"""Get collection by id.
Expand Down
31 changes: 26 additions & 5 deletions stac_fastapi/sqlalchemy/stac_fastapi/sqlalchemy/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from datetime import datetime
from typing import List, Optional, Set, Type, Union
from urllib.parse import urlencode
from urllib.parse import urlencode, urljoin

import attr
import geoalchemy2 as ga
Expand All @@ -17,6 +17,7 @@
from sqlalchemy import func
from sqlalchemy.orm import Session as SqlSession
from stac_pydantic.links import Relations
from stac_pydantic.shared import MimeTypes
from stac_pydantic.version import STAC_VERSION

from stac_fastapi.sqlalchemy import serializers
Expand All @@ -27,7 +28,7 @@
from stac_fastapi.types.config import Settings
from stac_fastapi.types.core import BaseCoreClient
from stac_fastapi.types.errors import NotFoundError
from stac_fastapi.types.stac import Collection, Item, ItemCollection
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -58,16 +59,36 @@ def _lookup_id(
raise NotFoundError(f"{table.__name__} {id} not found")
return row

def all_collections(self, **kwargs) -> List[Collection]:
def all_collections(self, **kwargs) -> Collections:
"""Read all collections from the database."""
base_url = str(kwargs["request"].base_url)
with self.session.reader.context_session() as session:
collections = session.query(self.collection_table).all()
response = [
serialized_collections = [
self.collection_serializer.db_to_stac(collection, base_url=base_url)
for collection in collections
]
return response
links = [
{
"rel": Relations.root.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.parent.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.self.value,
"type": MimeTypes.json,
"href": urljoin(base_url, "collections"),
},
]
collection_list = Collections(
collections=serialized_collections or [], links=links
)
return collection_list

def get_collection(self, id: str, **kwargs) -> Collection:
"""Get collection by id."""
Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/sqlalchemy/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Config:
def cleanup(postgres_core: CoreCrudClient, postgres_transactions: TransactionsClient):
yield
collections = postgres_core.all_collections(request=MockStarletteRequest)
for coll in collections:
for coll in collections["collections"]:
if coll["id"].split("-")[0] == "test":
# Delete the items
items = postgres_core.item_collection(
Expand Down
10 changes: 5 additions & 5 deletions stac_fastapi/types/stac_fastapi/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def landing_page(self, **kwargs) -> stac_types.LandingPage:

# Add Collections links
collections = self.all_collections(request=kwargs["request"])
for collection in collections:
for collection in collections["collections"]:
landing_page["links"].append(
{
"rel": Relations.child.value,
Expand Down Expand Up @@ -444,7 +444,7 @@ def get_item(self, item_id: str, collection_id: str, **kwargs) -> stac_types.Ite
...

@abc.abstractmethod
def all_collections(self, **kwargs) -> List[stac_types.Collection]:
def all_collections(self, **kwargs) -> stac_types.Collections:
"""Get all available collections.

Called with `GET /collections`.
Expand Down Expand Up @@ -540,12 +540,12 @@ async def landing_page(self, **kwargs) -> stac_types.LandingPage:
extension_schemas=extension_schemas,
)
collections = await self.all_collections(request=kwargs["request"])
for collection in collections:
for collection in collections["collections"]:
landing_page["links"].append(
{
"rel": Relations.child.value,
"type": MimeTypes.json.value,
"title": collection.get("title"),
"title": collection.get("title") or collection.get("id"),
"href": urljoin(base_url, f"collections/{collection['id']}"),
}
)
Expand Down Expand Up @@ -629,7 +629,7 @@ async def get_item(
...

@abc.abstractmethod
async def all_collections(self, **kwargs) -> List[stac_types.Collection]:
async def all_collections(self, **kwargs) -> stac_types.Collections:
lossyrob marked this conversation as resolved.
Show resolved Hide resolved
"""Get all available collections.

Called with `GET /collections`.
Expand Down
10 changes: 10 additions & 0 deletions stac_fastapi/types/stac_fastapi/types/stac.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,13 @@ class ItemCollection(TypedDict, total=False):
features: List[Item]
links: List[Dict[str, Any]]
context: Optional[Dict[str, int]]


class Collections(TypedDict, total=False):
"""All collections endpoint.

https://github.com/radiantearth/stac-api-spec/tree/master/collections
"""

collections: List[Collection]
links: List[Dict[str, Any]]