Skip to content

Commit

Permalink
update from main
Browse files Browse the repository at this point in the history
  • Loading branch information
vincentsarago committed Jul 1, 2024
2 parents a6d149b + 1062ac4 commit 7d7e8ce
Show file tree
Hide file tree
Showing 18 changed files with 416 additions and 64 deletions.
28 changes: 27 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,35 @@

## [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)

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

### Fixed

* Updated default filter language in filter extension's POST search request model to match the extension's documentation [#711](https://github.com/stac-utils/stac-fastapi/issues/711)

### Removed

* Removed the Filter Extension depenency from `AggregationExtensionPostRequest` and `AggregationExtensionGetRequest` [#716](https://github.com/stac-utils/stac-fastapi/pull/716)
* Removed `add_middleware` method in `StacApi` object and let starlette handle the middleware stack creation [721](https://github.com/stac-utils/stac-fastapi/pull/721)

## [3.0.0a3] - 2024-06-13

### Added
Expand Down Expand Up @@ -402,7 +427,8 @@

* First PyPi release!

[Unreleased]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a3..main>
[Unreleased]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a4..main>
[3.0.0a4]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a3..3.0.0a4>
[3.0.0a3]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a2..3.0.0a3>
[3.0.0a2]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a1..3.0.0a2>
[3.0.0a1]: <https://github.com/stac-utils/stac-fastapi/compare/3.0.0a0..3.0.0a1>
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.0a3
3.0.0a4
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

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,
)
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ section-order = ["future", "standard-library", "third-party", "first-party", "lo
quote-style = "double"

[tool.bumpversion]
current_version = "3.0.0a3"
current_version = "3.0.0a4"
parse = """(?x)
(?P<major>\\d+)\\.
(?P<minor>\\d+)\\.
Expand Down
45 changes: 22 additions & 23 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,
)
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 Expand Up @@ -439,11 +440,6 @@ def add_route_dependencies(
"""
return add_route_dependencies(self.app.router.routes, scopes, dependencies)

def add_middleware(self, middleware: Middleware):
"""Add a middleware class to the application."""
self.app.user_middleware.insert(0, middleware)
self.app.middleware_stack = self.app.build_middleware_stack()

def __attrs_post_init__(self):
"""Post-init hook.
Expand Down Expand Up @@ -483,8 +479,11 @@ def __attrs_post_init__(self):
self.app.openapi = self.customize_openapi

# add middlewares
if self.middlewares and self.app.middleware_stack is not None:
raise RuntimeError("Cannot add middleware after an application has started")

for middleware in self.middlewares:
self.add_middleware(middleware)
self.app.user_middleware.insert(0, middleware)

# customize route dependencies
for scopes, dependencies in self.route_dependencies:
Expand Down
26 changes: 0 additions & 26 deletions stac_fastapi/api/stac_fastapi/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,32 +120,6 @@ def __post_init__(self):
self.datetime = str_to_interval(self.datetime) # type: ignore


class POSTTokenPagination(BaseModel):
"""Token pagination model for POST requests."""

token: Optional[str] = None


@dataclass
class GETTokenPagination(APIRequest):
"""Token pagination for GET requests."""

token: Annotated[Optional[str], Query()] = None


class POSTPagination(BaseModel):
"""Page based pagination for POST requests."""

page: Optional[str] = None


@dataclass
class GETPagination(APIRequest):
"""Page based pagination for GET requests."""

page: Annotated[Optional[str], Query()] = None


# Test for ORJSON and use it rather than stdlib JSON where supported
if importlib.util.find_spec("orjson") is not None:
from fastapi.responses import ORJSONResponse
Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/api/stac_fastapi/api/version.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
"""Library version."""
__version__ = "3.0.0a3"
__version__ = "3.0.0a4"
Loading

0 comments on commit 7d7e8ce

Please sign in to comment.