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

remove pagination extension dependency and add request model attributes #718

Merged
merged 4 commits into from
Jul 1, 2024
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
16 changes: 15 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,23 @@

## [Unreleased] - TBD

### Added

* Add attributes to `stac_fastapi.api.app.StacApi` to enable customization of request model for:
- `/collections`: **collections_get_request_model**, default to `EmptyRequest`
- `/collections/{collection_id}`: **collection_get_request_model**, default to `CollectionUri`
- `/collections/{collection_id}/items`: **items_get_request_model**, default to `ItemCollectionUri`
- `/collections/{collection_id}/items/{item_id}`: **item_get_request_model**, default to `ItemUri`

### Removed

* Removed the Filter Extension dependency from `AggregationExtensionPostRequest` and `AggregationExtensionGetRequest` [#716](https://github.com/stac-utils/stac-fastapi/pull/716)
* Removed `pagination_extension` attribute in `stac_fastapi.api.app.StacApi`
* Removed use of `pagination_extension` in `register_get_item_collection` function (User now need to construct the request model and pass it using `items_get_request_model` attribute)

### Changed

* moved `GETPagination`, `POSTPagination`, `GETTokenPagination` and `POSTTokenPagination` to `stac_fastapi.extensions.core.pagination.request` submodule [#717](https://github.com/stac-utils/stac-fastapi/pull/717)
* Moved `GETPagination`, `POSTPagination`, `GETTokenPagination` and `POSTTokenPagination` to `stac_fastapi.extensions.core.pagination.request` submodule [#717](https://github.com/stac-utils/stac-fastapi/pull/717)

## [3.0.0a4] - 2024-06-27

Expand Down
2 changes: 2 additions & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ nav:
- search: api/stac_fastapi/types/search.md
- stac: api/stac_fastapi/types/stac.md
- version: api/stac_fastapi/types/version.md
- Migration Guides:
- v2.5 -> v3.0: migrations/v3.0.0.md
- Performance Benchmarks: benchmarks.html
- Development - Contributing: "contributing.md"
- Release Notes: "release-notes.md"
Expand Down
163 changes: 163 additions & 0 deletions docs/src/migrations/v3.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@

# stac-fastapi v3.0 Migration Guide
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved

This document aims to help you update your application from **stac-fastapi** 2.5 to 3.0.0.

## Dependencies

- **pydantic~=2.0**
- **fastapi>=0.111**
- **stac-pydantic~=3.1**

Most of the **stac-fastapi's** dependencies have been upgraded. Moving from pydantic v1 to v2 is mostly the one update bringing most breaking changes (see https://docs.pydantic.dev/latest/migration/).

In addition to pydantic v2 update, `stac-pydantic` has been updated to better match the STAC and STAC-API specifications (see https://github.com/stac-utils/stac-pydantic/blob/main/CHANGELOG.md#310-2024-05-21)


## Deprecation

* the `ContextExtension` have been removed (see https://github.com/stac-utils/stac-pydantic/pull/138) and was replaced by optional `NumberMatched` and `NumberReturned` attributes, defined by the OGC features specification.

* `stac_fastapi.api.config_openapi` method was removed (see https://github.com/stac-utils/stac-fastapi/pull/523)

* passing `response_class` in `stac_fastapi.api.routes.create_async_endpoint` is now deprecated. The response class now has to be set when registering the endpoint to the application (see https://github.com/stac-utils/stac-fastapi/issues/461)

* `PostFieldsExtension.filter_fields` property has been removed.

## Middlewares configuration

The `StacApi.middlewares` attribute has been updated to accept a list of `starlette.middleware.Middleware`. This enables dynamic configuration of middlewares (see https://github.com/stac-utils/stac-fastapi/pull/442).

```python
# before
class myMiddleware(mainMiddleware):
option1 = option1
option2 = option2

stac = StacApi(
middlewares=[
myMiddleware,
]
)

# now
stac = StacApi(
middlewares=[
Middleware(myMiddleware, option1, option2),
]
)
```

## Request Models

In stac-fastapi v2.0, users could already customize both GET/POST search request models. For v3.0, we've added more attributes to enable other endpoints customization:

- `collections_get_request_model`: GET request model for the `/collections` endpoint (default to `EmptyRequest`)
- `collection_get_request_model`: GET request model for the `/collections/{collection_id}` endpoint (default to `stac_fastapi.api.models.CollectionUri`)
- `items_get_request_model`: GET request model for the `/collections/{collection_id}/items` endpoint (default to `stac_fastapi.api.models.ItemCollectionUri`)
- `item_get_request_model`: GET request model for the `/collections/{collection_id}/items/{item_id}` endpoint (default to `stac_fastapi.api.models.ItemUri`)

```python
# before
getSearchModel = create_request_model(
model_name="SearchGetRequest",
base_model=BaseSearchGetRequest
extensions=[...],
request_type="GET"
)
stac = StacApi(
search_get_request_model=getSearchModel,
search_post_request_model=...,
)

# now
@dataclass
class CollectionsRequest(APIRequest):
user: str = Query(...)

stac = StacApi(
search_get_request_model=getSearchModel,
search_post_request_model=postSearchModel,
collections_get_request_model=CollectionsRequest,
collection_get_request_model=...,
items_get_request_model=...,
item_get_request_model=...,
)
```

## Filter extension

`default_includes` attribute has been removed from the `ApiSettings` object. If you need `defaults` includes you can overwrite the `FieldExtension` models (see https://github.com/stac-utils/stac-fastapi/pull/706).

```python
# before
stac = StacApi(
extensions=[
FieldsExtension()
]
)

# now
class PostFieldsExtension(requests.PostFieldsExtension):
include: Optional[Set[str]] = Field(
default_factory=lambda: {
"id",
"type",
"stac_version",
"geometry",
"bbox",
"links",
"assets",
"properties.datetime",
"collection",
}
)
exclude: Optional[Set[str]] = set()


class FieldsExtensionPostRequest(BaseModel):
"""Additional fields and schema for the POST request."""

fields: Optional[PostFieldsExtension] = Field(PostFieldsExtension())


class FieldsExtension(FieldsExtensionBase):
"""Override the POST model"""

POST = FieldsExtensionPostRequest


from stac_fastapi.api.app import StacApi

stac = StacApi(
extensions=[
FieldsExtension()
]
)
```

## Pagination extension

In stac-fastapi v3.0, we removed the `pagination_extension` attribute in `stac_fastapi.api.app.StacApi`. This attribute was used within the `register_get_item_collection` to update the request model for the `/collections/{collection_id}/items` endpoint.

It's now up to the user to create the request model and use the `items_get_request_model=` attribute in the StacApi object.

```python
# before
stac=StacApi(
pagination_extension=TokenPaginationExtension,
extension=[TokenPaginationExtension]
)

# now
items_get_request_model = create_request_model(
"ItemCollectionURI",
base_model=ItemCollectionUri,
mixins=[TokenPaginationExtension().GET],
)

stac=StacApi(
extension=[TokenPaginationExtension],
items_get_request_model=items_get_request_model,
)
```
35 changes: 18 additions & 17 deletions stac_fastapi/api/stac_fastapi/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
from stac_fastapi.api.errors import DEFAULT_STATUS_CODES, add_exception_handlers
from stac_fastapi.api.middleware import CORSMiddleware, ProxyHeaderMiddleware
from stac_fastapi.api.models import (
APIRequest,
CollectionUri,
EmptyRequest,
GeoJSONResponse,
ItemCollectionUri,
ItemUri,
create_request_model,
)
from stac_fastapi.api.openapi import update_openapi
from stac_fastapi.api.routes import Scope, add_route_dependencies, create_async_endpoint

# TODO: make this module not depend on `stac_fastapi.extensions`
from stac_fastapi.extensions.core import FieldsExtension, TokenPaginationExtension
from stac_fastapi.extensions.core import FieldsExtension
from stac_fastapi.types.config import ApiSettings, Settings
from stac_fastapi.types.core import AsyncBaseCoreClient, BaseCoreClient
from stac_fastapi.types.extension import ApiExtension
Expand Down Expand Up @@ -108,7 +108,10 @@ class StacApi:
search_post_request_model: Type[BaseSearchPostRequest] = attr.ib(
default=BaseSearchPostRequest
)
pagination_extension = attr.ib(default=TokenPaginationExtension)
collections_get_request_model: Type[APIRequest] = attr.ib(default=EmptyRequest)
collection_get_request_model: Type[APIRequest] = attr.ib(default=CollectionUri)
items_get_request_model: Type[APIRequest] = attr.ib(default=ItemCollectionUri)
item_get_request_model: Type[APIRequest] = attr.ib(default=ItemUri)
response_class: Type[Response] = attr.ib(default=JSONResponse)
middlewares: List[Middleware] = attr.ib(
default=attr.Factory(
Expand Down Expand Up @@ -211,7 +214,9 @@ def register_get_item(self):
response_model_exclude_unset=True,
response_model_exclude_none=True,
methods=["GET"],
endpoint=create_async_endpoint(self.client.get_item, ItemUri),
endpoint=create_async_endpoint(
self.client.get_item, self.item_get_request_model
),
)

def register_post_search(self):
Expand Down Expand Up @@ -302,7 +307,9 @@ def register_get_collections(self):
response_model_exclude_unset=True,
response_model_exclude_none=True,
methods=["GET"],
endpoint=create_async_endpoint(self.client.all_collections, EmptyRequest),
endpoint=create_async_endpoint(
self.client.all_collections, self.collections_get_request_model
),
)

def register_get_collection(self):
Expand All @@ -329,7 +336,9 @@ def register_get_collection(self):
response_model_exclude_unset=True,
response_model_exclude_none=True,
methods=["GET"],
endpoint=create_async_endpoint(self.client.get_collection, CollectionUri),
endpoint=create_async_endpoint(
self.client.get_collection, self.collection_get_request_model
),
)

def register_get_item_collection(self):
Expand All @@ -338,16 +347,6 @@ def register_get_item_collection(self):
Returns:
None
"""
pagination_extension = self.get_extension(self.pagination_extension)
if pagination_extension is not None:
mixins = [pagination_extension.GET]
else:
mixins = None
request_model = create_request_model(
"ItemCollectionURI",
base_model=ItemCollectionUri,
mixins=mixins,
)
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved
self.router.add_api_route(
name="Get ItemCollection",
path="/collections/{collection_id}/items",
Expand All @@ -366,7 +365,9 @@ def register_get_item_collection(self):
response_model_exclude_unset=True,
response_model_exclude_none=True,
methods=["GET"],
endpoint=create_async_endpoint(self.client.item_collection, request_model),
endpoint=create_async_endpoint(
self.client.item_collection, self.items_get_request_model
),
)

def register_core(self):
Expand Down
9 changes: 9 additions & 0 deletions stac_fastapi/api/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from starlette.testclient import TestClient

from stac_fastapi.api.app import StacApi
from stac_fastapi.api.models import ItemCollectionUri, create_request_model
from stac_fastapi.extensions.core import (
TokenPaginationExtension,
TransactionExtension,
Expand All @@ -13,6 +14,13 @@ class TestRouteDependencies:
@staticmethod
def _build_api(**overrides):
settings = config.ApiSettings()

items_get_request_model = create_request_model(
"ItemCollectionURI",
base_model=ItemCollectionUri,
mixins=[TokenPaginationExtension().GET],
)
vincentsarago marked this conversation as resolved.
Show resolved Hide resolved

return StacApi(
**{
"settings": settings,
Expand All @@ -23,6 +31,7 @@ def _build_api(**overrides):
),
TokenPaginationExtension(),
],
"items_get_request_model": items_get_request_model,
**overrides,
}
)
Expand Down
Loading