Skip to content

Commit 5de6249

Browse files
committed
remove pagination extension dependency and add request model attributes
1 parent f311dc6 commit 5de6249

File tree

4 files changed

+106
-19
lines changed

4 files changed

+106
-19
lines changed

CHANGES.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,23 @@
22

33
## [Unreleased] - TBD
44

5+
### Added
6+
7+
* Add attributes to `stac_fastapi.api.app.StacApi` to enable customization of request model for:
8+
- `/collections`: **collections_get_request_model**, default to `EmptyRequest`
9+
- `/collections/{collection_id}`: **collection_get_request_model**, default to `CollectionUri`
10+
- `/collections/{collection_id}/items`: **items_get_request_model**, default to `ItemCollectionUri`
11+
- `/collections/{collection_id}/items/{item_id}`: **item_get_request_model**, default to `ItemUri`
12+
513
### Fixed
614

715
* 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)
816

917
### Removed
1018

11-
* Removed the Filter Extension depenency from `AggregationExtensionPostRequest` and `AggregationExtensionGetRequest` [#716](https://github.com/stac-utils/stac-fastapi/pull/716)
19+
* Removed the Filter Extension dependency from `AggregationExtensionPostRequest` and `AggregationExtensionGetRequest` [#716](https://github.com/stac-utils/stac-fastapi/pull/716)
20+
* `pagination_extension` attribute in `stac_fastapi.api.app.StacApi`
21+
* remove 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)
1222

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

stac_fastapi/api/stac_fastapi/api/app.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
from stac_fastapi.api.errors import DEFAULT_STATUS_CODES, add_exception_handlers
1919
from stac_fastapi.api.middleware import CORSMiddleware, ProxyHeaderMiddleware
2020
from stac_fastapi.api.models import (
21+
APIRequest,
2122
CollectionUri,
2223
EmptyRequest,
2324
GeoJSONResponse,
2425
ItemCollectionUri,
2526
ItemUri,
26-
create_request_model,
2727
)
2828
from stac_fastapi.api.openapi import update_openapi
2929
from stac_fastapi.api.routes import Scope, add_route_dependencies, create_async_endpoint
3030

3131
# TODO: make this module not depend on `stac_fastapi.extensions`
32-
from stac_fastapi.extensions.core import FieldsExtension, TokenPaginationExtension
32+
from stac_fastapi.extensions.core import FieldsExtension
3333
from stac_fastapi.types.config import ApiSettings, Settings
3434
from stac_fastapi.types.core import AsyncBaseCoreClient, BaseCoreClient
3535
from stac_fastapi.types.extension import ApiExtension
@@ -108,7 +108,10 @@ class StacApi:
108108
search_post_request_model: Type[BaseSearchPostRequest] = attr.ib(
109109
default=BaseSearchPostRequest
110110
)
111-
pagination_extension = attr.ib(default=TokenPaginationExtension)
111+
collections_get_request_model: Type[APIRequest] = attr.ib(default=EmptyRequest)
112+
collection_get_request_model: Type[APIRequest] = attr.ib(default=CollectionUri)
113+
items_get_request_model: Type[APIRequest] = attr.ib(default=ItemCollectionUri)
114+
item_get_request_model: Type[APIRequest] = attr.ib(default=ItemUri)
112115
response_class: Type[Response] = attr.ib(default=JSONResponse)
113116
middlewares: List[Middleware] = attr.ib(
114117
default=attr.Factory(
@@ -211,7 +214,9 @@ def register_get_item(self):
211214
response_model_exclude_unset=True,
212215
response_model_exclude_none=True,
213216
methods=["GET"],
214-
endpoint=create_async_endpoint(self.client.get_item, ItemUri),
217+
endpoint=create_async_endpoint(
218+
self.client.get_item, self.item_get_request_model
219+
),
215220
)
216221

217222
def register_post_search(self):
@@ -302,7 +307,9 @@ def register_get_collections(self):
302307
response_model_exclude_unset=True,
303308
response_model_exclude_none=True,
304309
methods=["GET"],
305-
endpoint=create_async_endpoint(self.client.all_collections, EmptyRequest),
310+
endpoint=create_async_endpoint(
311+
self.client.all_collections, self.collections_get_request_model
312+
),
306313
)
307314

308315
def register_get_collection(self):
@@ -329,7 +336,9 @@ def register_get_collection(self):
329336
response_model_exclude_unset=True,
330337
response_model_exclude_none=True,
331338
methods=["GET"],
332-
endpoint=create_async_endpoint(self.client.get_collection, CollectionUri),
339+
endpoint=create_async_endpoint(
340+
self.client.get_collection, self.collection_get_request_model
341+
),
333342
)
334343

335344
def register_get_item_collection(self):
@@ -338,16 +347,6 @@ def register_get_item_collection(self):
338347
Returns:
339348
None
340349
"""
341-
pagination_extension = self.get_extension(self.pagination_extension)
342-
if pagination_extension is not None:
343-
mixins = [pagination_extension.GET]
344-
else:
345-
mixins = None
346-
request_model = create_request_model(
347-
"ItemCollectionURI",
348-
base_model=ItemCollectionUri,
349-
mixins=mixins,
350-
)
351350
self.router.add_api_route(
352351
name="Get ItemCollection",
353352
path="/collections/{collection_id}/items",
@@ -366,7 +365,9 @@ def register_get_item_collection(self):
366365
response_model_exclude_unset=True,
367366
response_model_exclude_none=True,
368367
methods=["GET"],
369-
endpoint=create_async_endpoint(self.client.item_collection, request_model),
368+
endpoint=create_async_endpoint(
369+
self.client.item_collection, self.items_get_request_model
370+
),
370371
)
371372

372373
def register_core(self):

stac_fastapi/api/tests/test_api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from starlette.testclient import TestClient
33

44
from stac_fastapi.api.app import StacApi
5+
from stac_fastapi.api.models import ItemCollectionUri, create_request_model
56
from stac_fastapi.extensions.core import (
67
TokenPaginationExtension,
78
TransactionExtension,
@@ -13,6 +14,13 @@ class TestRouteDependencies:
1314
@staticmethod
1415
def _build_api(**overrides):
1516
settings = config.ApiSettings()
17+
18+
items_get_request_model = create_request_model(
19+
"ItemCollectionURI",
20+
base_model=ItemCollectionUri,
21+
mixins=[TokenPaginationExtension().GET],
22+
)
23+
1624
return StacApi(
1725
**{
1826
"settings": settings,
@@ -23,6 +31,7 @@ def _build_api(**overrides):
2331
),
2432
TokenPaginationExtension(),
2533
],
34+
"items_get_request_model": items_get_request_model,
2635
**overrides,
2736
}
2837
)

stac_fastapi/api/tests/test_app.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1+
from dataclasses import dataclass
12
from datetime import datetime
23
from typing import List, Optional, Union
34

45
import pytest
6+
from fastapi import Path, Query
57
from fastapi.testclient import TestClient
68
from pydantic import ValidationError
79
from stac_pydantic import api
810

911
from stac_fastapi.api import app
10-
from stac_fastapi.api.models import create_get_request_model, create_post_request_model
12+
from stac_fastapi.api.models import (
13+
APIRequest,
14+
create_get_request_model,
15+
create_post_request_model,
16+
)
1117
from stac_fastapi.extensions.core import FieldsExtension, FilterExtension
1218
from stac_fastapi.types import stac
1319
from stac_fastapi.types.config import ApiSettings
@@ -294,3 +300,64 @@ def item_collection(
294300
else:
295301
assert get_search.status_code == 200, get_search.text
296302
assert post_search.status_code == 200, post_search.text
303+
304+
305+
def test_request_model(AsyncTestCoreClient):
306+
"""Test if request models are passed correctly."""
307+
308+
@dataclass
309+
class CollectionsRequest(APIRequest):
310+
user: str = Query(...)
311+
312+
@dataclass
313+
class CollectionRequest(APIRequest):
314+
collection_id: str = Path(description="Collection ID")
315+
user: str = Query(...)
316+
317+
@dataclass
318+
class ItemsRequest(APIRequest):
319+
collection_id: str = Path(description="Collection ID")
320+
user: str = Query(...)
321+
322+
@dataclass
323+
class ItemRequest(APIRequest):
324+
collection_id: str = Path(description="Collection ID")
325+
item_id: str = Path(description="Item ID")
326+
user: str = Query(...)
327+
328+
test_app = app.StacApi(
329+
settings=ApiSettings(),
330+
client=AsyncTestCoreClient(),
331+
collections_get_request_model=CollectionsRequest,
332+
collection_get_request_model=CollectionRequest,
333+
items_get_request_model=ItemsRequest,
334+
item_get_request_model=ItemRequest,
335+
extensions=[],
336+
)
337+
338+
with TestClient(test_app.app) as client:
339+
resp = client.get("/collections")
340+
assert resp.status_code == 400
341+
342+
resp = client.get("/collections", params={"user": "luke"})
343+
assert resp.status_code == 200
344+
345+
resp = client.get("/collections/test_collection")
346+
assert resp.status_code == 400
347+
348+
resp = client.get("/collections/test_collection", params={"user": "luke"})
349+
assert resp.status_code == 200
350+
351+
resp = client.get("/collections/test_collection/items")
352+
assert resp.status_code == 400
353+
354+
resp = client.get("/collections/test_collection/items", params={"user": "luke"})
355+
assert resp.status_code == 200
356+
357+
resp = client.get("/collections/test_collection/items/test_item")
358+
assert resp.status_code == 400
359+
360+
resp = client.get(
361+
"/collections/test_collection/items/test_item", params={"user": "luke"}
362+
)
363+
assert resp.status_code == 200

0 commit comments

Comments
 (0)