Skip to content

Commit 32b3c6d

Browse files
committed
Merge branch 'main' of https://github.com/stac-utils/stac-fastapi-pgstac into tests/add-paging-links-tests
2 parents 23be4cb + e063785 commit 32b3c6d

File tree

11 files changed

+104
-33
lines changed

11 files changed

+104
-33
lines changed

.github/workflows/packages.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ jobs:
2424
password: ${{ secrets.GITHUB_TOKEN }}
2525
- name: Extract metadata (tags, labels) for Docker
2626
id: meta
27-
uses: docker/metadata-action@v5.6.1
27+
uses: docker/metadata-action@v5.7.0
2828
with:
2929
images: ghcr.io/stac-utils/stac-fastapi-pgstac
3030
- name: Build and push Docker image
31-
uses: docker/build-push-action@v6.13.0
31+
uses: docker/build-push-action@v6.15.0
3232
with:
3333
context: .
3434
file: Dockerfile

CHANGES.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@
22

33
## [Unreleased]
44

5+
## [4.0.2] - 2025-02-18
6+
7+
### Fixed
8+
9+
- use Relation's `value` for `POST` prev/next links
10+
- return `JSONResponse` directly from `/items` endpoint when `fields` parameter is pass and avoid Pydantic validation
11+
12+
### Changed
13+
14+
- avoid re-use of internal `CoreCrudClient.post_search` in `CoreCrudClient.get_search` method to allow customization
15+
16+
## [4.0.1] - 2025-02-06
17+
18+
### Added
19+
20+
- add `numberReturned` and `numberMatched` in `/collections` response
21+
22+
## [4.0.0] - 2025-02-03
23+
524
### Changed
625

726
- remove `python 3.8` support
@@ -17,6 +36,8 @@
1736
### Fixed
1837

1938
- handle `next` and `dev` tokens now returned as links from pgstac>=0.9.0 (author @zstatmanweil, <https://github.com/stac-utils/stac-fastapi-pgstac/pull/140>)
39+
- fix Docker compose file, so example data can be loaded into database (author @zstatmanweil, <https://github.com/stac-utils/stac-fastapi-pgstac/pull/142>)
40+
- fix `filter` extension implementation in `CoreCrudClient`
2041

2142
### Added
2243

@@ -27,11 +48,6 @@
2748
- add [query extension](https://github.com/stac-api-extensions/query) support to Item Collection endpoint ([#162](https://github.com/stac-utils/stac-fastapi-pgstac/pull/192))
2849
- add [fields extension](https://github.com/stac-api-extensions/fields) support to Item Collection endpoint ([#162](https://github.com/stac-utils/stac-fastapi-pgstac/pull/192))
2950

30-
### Fixed
31-
32-
- fix Docker compose file, so example data can be loaded into database (author @zstatmanweil, <https://github.com/stac-utils/stac-fastapi-pgstac/pull/142>)
33-
- fix `filter` extension implementation in `CoreCrudClient`
34-
3551
## [3.0.1] - 2024-11-14
3652

3753
- Enable runtime `CORS` configuration using environment variables (`CORS_ORIGIN="https://...,https://..."`, `CORS_METHODS="PUT,OPTIONS"`) (<https://github.com/stac-utils/stac-fastapi-pgstac/pull/168>)
@@ -367,7 +383,10 @@ As a part of this release, this repository was extracted from the main
367383

368384
- First PyPi release!
369385

370-
[Unreleased]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/3.0.1..main>
386+
[Unreleased]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/4.0.2..main>
387+
[4.0.2]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/4.0.1..4.0.2>
388+
[4.0.1]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/4.0.0..4.0.1>
389+
[4.0.0]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/3.0.1..4.0.0>
371390
[3.0.1]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/3.0.0..3.0.1>
372391
[3.0.0]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/2.5.0..3.0.0>
373392
[2.5.0]: <https://github.com/stac-utils/stac-fastapi-pgstac/compare/2.4.11..2.5.0>

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.0.0
1+
4.0.2

docker-compose.nginx.yml

Lines changed: 0 additions & 13 deletions
This file was deleted.

docker-compose.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,23 @@ services:
7676
- database
7777
- app
7878

79+
nginx:
80+
image: nginx
81+
ports:
82+
- ${STAC_FASTAPI_NGINX_PORT:-8080}:80
83+
volumes:
84+
- ./nginx.conf:/etc/nginx/nginx.conf
85+
depends_on:
86+
- app-nginx
87+
command: [ "nginx-debug", "-g", "daemon off;" ]
88+
89+
app-nginx:
90+
extends:
91+
service: app
92+
command: bash -c "./scripts/wait-for-it.sh database:5432 && uvicorn stac_fastapi.pgstac.app:app --host 0.0.0.0 --port 8082 --proxy-headers --forwarded-allow-ips=*"
93+
environment:
94+
- ROOT_PATH=/api/v1/pgstac
95+
7996
networks:
8097
default:
8198
name: stac-fastapi-network

nginx.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ http {
66

77
location /api/v1/pgstac {
88
rewrite ^/api/v1/pgstac(.*)$ $1 break;
9-
proxy_pass http://app:8082;
10-
proxy_set_header HOST $host;
9+
proxy_pass http://app-nginx:8082;
10+
proxy_set_header HOST $http_host;
1111
proxy_set_header Referer $http_referer;
1212
proxy_set_header X-Forwarded-For $remote_addr;
1313
proxy_set_header X-Forwarded-Proto $scheme;

stac_fastapi/pgstac/core.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ async def all_collections( # noqa: C901
148148
return Collections(
149149
collections=linked_collections or [],
150150
links=links,
151+
numberMatched=collections_result.get(
152+
"numberMatched", len(linked_collections)
153+
),
154+
numberReturned=collections_result.get(
155+
"numberReturned", len(linked_collections)
156+
),
151157
)
152158

153159
async def get_collection(
@@ -387,15 +393,28 @@ async def item_collection(
387393
sortby=sortby,
388394
)
389395

390-
search_request = self.pgstac_search_model(**clean)
396+
try:
397+
search_request = self.pgstac_search_model(**clean)
398+
except ValidationError as e:
399+
raise HTTPException(
400+
status_code=400, detail=f"Invalid parameters provided {e}"
401+
) from e
402+
391403
item_collection = await self._search_base(search_request, request=request)
392404

393405
links = await ItemCollectionLinks(
394406
collection_id=collection_id, request=request
395407
).get_links(extra_links=item_collection["links"])
396408
item_collection["links"] = links
397409

398-
return item_collection
410+
# If we have the `fields` extension enabled
411+
# we need to avoid Pydantic validation because the
412+
# Items might not be a valid STAC Item objects
413+
if fields := getattr(search_request, "fields", None):
414+
if fields.include or fields.exclude:
415+
return JSONResponse(item_collection) # type: ignore
416+
417+
return ItemCollection(**item_collection)
399418

400419
async def get_item(
401420
self, item_id: str, collection_id: str, request: Request, **kwargs
@@ -494,15 +513,23 @@ async def get_search(
494513
filter_lang=filter_lang,
495514
)
496515

497-
# Do the request
498516
try:
499517
search_request = self.pgstac_search_model(**clean)
500518
except ValidationError as e:
501519
raise HTTPException(
502520
status_code=400, detail=f"Invalid parameters provided {e}"
503521
) from e
504522

505-
return await self.post_search(search_request, request=request)
523+
item_collection = await self._search_base(search_request, request=request)
524+
525+
# If we have the `fields` extension enabled
526+
# we need to avoid Pydantic validation because the
527+
# Items might not be a valid STAC Item objects
528+
if fields := getattr(search_request, "fields", None):
529+
if fields.include or fields.exclude:
530+
return JSONResponse(item_collection) # type: ignore
531+
532+
return ItemCollection(**item_collection)
506533

507534
def _clean_search_args( # noqa: C901
508535
self,

stac_fastapi/pgstac/models/links.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ def link_next(self) -> Optional[Dict[str, Any]]:
140140

141141
if method == "POST":
142142
return {
143-
"rel": Relations.next,
144-
"type": MimeTypes.geojson,
143+
"rel": Relations.next.value,
144+
"type": MimeTypes.geojson.value,
145145
"method": method,
146146
"href": str(self.request.url),
147147
"body": {**self.request.postbody, "token": f"next:{self.next}"},
@@ -164,8 +164,8 @@ def link_prev(self) -> Optional[Dict[str, Any]]:
164164

165165
if method == "POST":
166166
return {
167-
"rel": Relations.previous,
168-
"type": MimeTypes.geojson,
167+
"rel": Relations.previous.value,
168+
"type": MimeTypes.geojson.value,
169169
"method": method,
170170
"href": str(self.request.url),
171171
"body": {**self.request.postbody, "token": f"prev:{self.prev}"},

stac_fastapi/pgstac/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""library version."""
22

3-
__version__ = "3.0.0"
3+
__version__ = "4.0.2"

tests/resources/test_collection.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ async def test_nocollections(
116116
):
117117
resp = await app_client.get("/collections")
118118
assert resp.status_code == 200
119+
assert resp.json()["numberReturned"] == 0
119120

120121

121122
async def test_returns_valid_collection(app_client, load_test_data):
@@ -168,6 +169,9 @@ async def test_returns_valid_links_in_collections(app_client, load_test_data):
168169
resp = await app_client.get("/collections")
169170
assert resp.status_code == 200
170171
resp_json = resp.json()
172+
assert resp.json()["numberReturned"]
173+
assert resp.json()["numberMatched"]
174+
171175
collections = resp_json["collections"]
172176
# Find collection in list by ID
173177
single_coll = next(coll for coll in collections if coll["id"] == in_json["id"])
@@ -317,6 +321,8 @@ async def test_collection_search_freetext(
317321
"/collections",
318322
params={"q": "temperature"},
319323
)
324+
assert resp.json()["numberReturned"] == 1
325+
assert resp.json()["numberMatched"] == 1
320326
assert len(resp.json()["collections"]) == 1
321327
assert resp.json()["collections"][0]["id"] == load_test2_collection.id
322328

@@ -341,13 +347,17 @@ async def test_all_collections_with_pagination(app_client, load_test_data):
341347
assert resp.status_code == 201
342348

343349
resp = await app_client.get("/collections")
350+
assert resp.json()["numberReturned"] == 10
351+
assert resp.json()["numberMatched"] == 12
344352
cols = resp.json()["collections"]
345353
assert len(cols) == 10
346354
links = resp.json()["links"]
347355
assert len(links) == 3
348356
assert {"root", "self", "next"} == {link["rel"] for link in links}
349357

350358
resp = await app_client.get("/collections", params={"limit": 12})
359+
assert resp.json()["numberReturned"] == 12
360+
assert resp.json()["numberMatched"] == 12
351361
cols = resp.json()["collections"]
352362
assert len(cols) == 12
353363
links = resp.json()["links"]
@@ -369,6 +379,8 @@ async def test_all_collections_without_pagination(app_client_no_ext, load_test_d
369379
assert resp.status_code == 201
370380

371381
resp = await app_client_no_ext.get("/collections")
382+
assert resp.json()["numberReturned"] == 12
383+
assert resp.json()["numberMatched"] == 12
372384
cols = resp.json()["collections"]
373385
assert len(cols) == 12
374386
links = resp.json()["links"]
@@ -382,6 +394,8 @@ async def test_get_collections_search_pagination(
382394
app_client, load_test_collection, load_test2_collection
383395
):
384396
resp = await app_client.get("/collections")
397+
assert resp.json()["numberReturned"] == 2
398+
assert resp.json()["numberMatched"] == 2
385399
cols = resp.json()["collections"]
386400
assert len(cols) == 2
387401
links = resp.json()["links"]

0 commit comments

Comments
 (0)