stac-fastapi-core 6.5.1__tar.gz → 6.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. stac_fastapi_core-6.7.0/.gitignore +143 -0
  2. stac_fastapi_core-6.7.0/PKG-INFO +66 -0
  3. stac_fastapi_core-6.7.0/README.md +32 -0
  4. stac_fastapi_core-6.7.0/pyproject.toml +60 -0
  5. stac_fastapi_core-6.7.0/pytest.ini +4 -0
  6. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/base_database_logic.py +14 -2
  7. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/core.py +102 -48
  8. stac_fastapi_core-6.7.0/stac_fastapi/core/extensions/collections_search.py +384 -0
  9. stac_fastapi_core-6.7.0/stac_fastapi/core/redis_utils.py +301 -0
  10. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/serializers.py +6 -0
  11. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/utilities.py +1 -9
  12. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/version.py +1 -1
  13. stac_fastapi_core-6.5.1/PKG-INFO +0 -713
  14. stac_fastapi_core-6.5.1/README.md +0 -695
  15. stac_fastapi_core-6.5.1/setup.cfg +0 -7
  16. stac_fastapi_core-6.5.1/setup.py +0 -46
  17. stac_fastapi_core-6.5.1/stac_fastapi/core/extensions/collections_search.py +0 -194
  18. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/PKG-INFO +0 -713
  19. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/SOURCES.txt +0 -30
  20. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/dependency_links.txt +0 -1
  21. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/not-zip-safe +0 -1
  22. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/requires.txt +0 -13
  23. stac_fastapi_core-6.5.1/stac_fastapi_core.egg-info/top_level.txt +0 -1
  24. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/__init__.py +0 -0
  25. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/base_settings.py +0 -0
  26. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/basic_auth.py +0 -0
  27. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/datetime_utils.py +0 -0
  28. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/extensions/__init__.py +0 -0
  29. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/extensions/aggregation.py +0 -0
  30. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/extensions/fields.py +0 -0
  31. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/extensions/filter.py +0 -0
  32. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/extensions/query.py +0 -0
  33. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/models/__init__.py +0 -0
  34. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/models/links.py +0 -0
  35. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/models/search.py +0 -0
  36. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/rate_limit.py +0 -0
  37. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/route_dependencies.py +0 -0
  38. {stac_fastapi_core-6.5.1 → stac_fastapi_core-6.7.0}/stac_fastapi/core/session.py +0 -0
@@ -0,0 +1,143 @@
1
+ elasticsearch/snapshots/
2
+
3
+ # Byte-compiled / optimized / DLL files
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ pip-wheel-metadata/
26
+ share/python-wheels/
27
+ *.egg-info/
28
+ .installed.cfg
29
+ *.egg
30
+ MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ *.manifest
36
+ *.spec
37
+
38
+ # Installer logs
39
+ pip-log.txt
40
+ pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ htmlcov/
44
+ .tox/
45
+ .nox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ *.py,cover
53
+ .hypothesis/
54
+ .pytest_cache/
55
+
56
+ # Translations
57
+ *.mo
58
+ *.pot
59
+
60
+ # Django stuff:
61
+ *.log
62
+ local_settings.py
63
+ db.sqlite3
64
+ db.sqlite3-journal
65
+
66
+ # Flask stuff:
67
+ instance/
68
+ .webassets-cache
69
+
70
+ # Scrapy stuff:
71
+ .scrapy
72
+
73
+ # Sphinx documentation
74
+ docs/_build/
75
+
76
+ # PyBuilder
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ .python-version
88
+
89
+ # pipenv
90
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
92
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
93
+ # install all needed dependencies.
94
+ #Pipfile.lock
95
+
96
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
97
+ __pypackages__/
98
+
99
+ # Celery stuff
100
+ celerybeat-schedule
101
+ celerybeat.pid
102
+
103
+ # SageMath parsed files
104
+ *.sage.py
105
+
106
+ # Environments
107
+ .env
108
+ .venv
109
+ env/
110
+ venv/
111
+ ENV/
112
+ env.bak/
113
+ venv.bak/
114
+
115
+ # Spyder project settings
116
+ .spyderproject
117
+ .spyproject
118
+
119
+ # Rope project settings
120
+ .ropeproject
121
+
122
+ # mkdocs documentation
123
+ /site
124
+
125
+ # mypy
126
+ .mypy_cache/
127
+ .dmypy.json
128
+ dmypy.json
129
+
130
+ # Pyre type checker
131
+ .pyre/
132
+
133
+ /esdata
134
+
135
+ # Virtualenv
136
+ venv
137
+
138
+ # VSCode folder
139
+ .vscode
140
+
141
+ /docs/src/api/*
142
+
143
+ .DS_Store
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: stac_fastapi_core
3
+ Version: 6.7.0
4
+ Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
5
+ Project-URL: Homepage, https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
6
+ License: MIT
7
+ Keywords: Elasticsearch,FastAPI,Opensearch,STAC,STAC-API,stac-fastapi
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Information Technology
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: >=3.9
19
+ Requires-Dist: attrs>=23.2.0
20
+ Requires-Dist: fastapi~=0.109.0
21
+ Requires-Dist: geojson-pydantic~=1.0.0
22
+ Requires-Dist: jsonschema~=4.0.0
23
+ Requires-Dist: orjson~=3.11.0
24
+ Requires-Dist: overrides~=7.4.0
25
+ Requires-Dist: pydantic<3.0.0,>=2.4.1
26
+ Requires-Dist: pygeofilter~=0.3.1
27
+ Requires-Dist: redis==6.4.0
28
+ Requires-Dist: slowapi~=0.1.9
29
+ Requires-Dist: stac-fastapi-api==6.0.0
30
+ Requires-Dist: stac-fastapi-extensions==6.0.0
31
+ Requires-Dist: stac-fastapi-types==6.0.0
32
+ Requires-Dist: stac-pydantic~=3.3.0
33
+ Description-Content-Type: text/markdown
34
+
35
+ # stac-fastapi-core
36
+
37
+ <p align="left">
38
+ <img src="https://raw.githubusercontent.com/stac-utils/stac-fastapi-elasticsearch-opensearch/refs/heads/main/assets/sfeos.png" width=1000>
39
+ </p>
40
+
41
+ [![Downloads](https://static.pepy.tech/badge/stac-fastapi-core?color=blue)](https://pepy.tech/project/stac-fastapi-core)
42
+ [![GitHub contributors](https://img.shields.io/github/contributors/stac-utils/stac-fastapi-elasticsearch-opensearch?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/graphs/contributors)
43
+ [![GitHub stars](https://img.shields.io/github/stars/stac-utils/stac-fastapi-elasticsearch-opensearch.svg?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/stargazers)
44
+ [![GitHub forks](https://img.shields.io/github/forks/stac-utils/stac-fastapi-elasticsearch-opensearch.svg?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/network/members)
45
+ [![PyPI version](https://img.shields.io/pypi/v/stac-fastapi-elasticsearch.svg?color=blue)](https://pypi.org/project/stac-fastapi-elasticsearch/)
46
+ [![STAC](https://img.shields.io/badge/STAC-1.1.0-blue.svg)](https://github.com/radiantearth/stac-spec/tree/v1.1.0)
47
+ [![stac-fastapi](https://img.shields.io/badge/stac--fastapi-6.0.0-blue.svg)](https://github.com/stac-utils/stac-fastapi)
48
+
49
+ Core functionality for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
50
+
51
+ ## Package Information
52
+
53
+ - **Package name**: stac-fastapi-core
54
+ - **Description**: Core functionality for STAC API implementations.
55
+ - **Documentation**: [https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/)
56
+ - **Source**: [GitHub Repository](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/)
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install stac-fastapi-core
62
+ ```
63
+
64
+ ## Quick Start
65
+
66
+ For detailed usage and examples, please refer to the [main documentation](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/).
@@ -0,0 +1,32 @@
1
+ # stac-fastapi-core
2
+
3
+ <p align="left">
4
+ <img src="https://raw.githubusercontent.com/stac-utils/stac-fastapi-elasticsearch-opensearch/refs/heads/main/assets/sfeos.png" width=1000>
5
+ </p>
6
+
7
+ [![Downloads](https://static.pepy.tech/badge/stac-fastapi-core?color=blue)](https://pepy.tech/project/stac-fastapi-core)
8
+ [![GitHub contributors](https://img.shields.io/github/contributors/stac-utils/stac-fastapi-elasticsearch-opensearch?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/graphs/contributors)
9
+ [![GitHub stars](https://img.shields.io/github/stars/stac-utils/stac-fastapi-elasticsearch-opensearch.svg?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/stargazers)
10
+ [![GitHub forks](https://img.shields.io/github/forks/stac-utils/stac-fastapi-elasticsearch-opensearch.svg?color=blue)](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/network/members)
11
+ [![PyPI version](https://img.shields.io/pypi/v/stac-fastapi-elasticsearch.svg?color=blue)](https://pypi.org/project/stac-fastapi-elasticsearch/)
12
+ [![STAC](https://img.shields.io/badge/STAC-1.1.0-blue.svg)](https://github.com/radiantearth/stac-spec/tree/v1.1.0)
13
+ [![stac-fastapi](https://img.shields.io/badge/stac--fastapi-6.0.0-blue.svg)](https://github.com/stac-utils/stac-fastapi)
14
+
15
+ Core functionality for stac-fastapi. For full documentation, please see the [main README](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/blob/main/README.md).
16
+
17
+ ## Package Information
18
+
19
+ - **Package name**: stac-fastapi-core
20
+ - **Description**: Core functionality for STAC API implementations.
21
+ - **Documentation**: [https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/)
22
+ - **Source**: [GitHub Repository](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/)
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install stac-fastapi-core
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ For detailed usage and examples, please refer to the [main documentation](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/).
@@ -0,0 +1,60 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "stac_fastapi_core"
7
+ description = "Core library for the Elasticsearch and Opensearch stac-fastapi backends."
8
+ readme = "README.md"
9
+ requires-python = ">=3.9"
10
+ license = {text = "MIT"}
11
+ authors = []
12
+ classifiers = [
13
+ "Intended Audience :: Developers",
14
+ "Intended Audience :: Information Technology",
15
+ "Intended Audience :: Science/Research",
16
+ "Programming Language :: Python :: 3.9",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ "License :: OSI Approved :: MIT License",
23
+ ]
24
+ keywords = [
25
+ "STAC",
26
+ "STAC-API",
27
+ "FastAPI",
28
+ "stac-fastapi",
29
+ "Elasticsearch",
30
+ "Opensearch",
31
+ ]
32
+ dynamic = ["version"]
33
+ dependencies = [
34
+ "fastapi~=0.109.0",
35
+ "attrs>=23.2.0",
36
+ "pydantic>=2.4.1,<3.0.0",
37
+ "stac_pydantic~=3.3.0",
38
+ "stac-fastapi.types==6.0.0",
39
+ "stac-fastapi.api==6.0.0",
40
+ "stac-fastapi.extensions==6.0.0",
41
+ "orjson~=3.11.0",
42
+ "overrides~=7.4.0",
43
+ "geojson-pydantic~=1.0.0",
44
+ "pygeofilter~=0.3.1",
45
+ "jsonschema~=4.0.0",
46
+ "slowapi~=0.1.9",
47
+ "redis==6.4.0",
48
+ ]
49
+
50
+ [project.urls]
51
+ Homepage = "https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch"
52
+
53
+ [tool.hatch.version]
54
+ path = "stac_fastapi/core/version.py"
55
+
56
+ [tool.hatch.build.targets.sdist]
57
+ exclude = ["alembic", "tests", "scripts"]
58
+
59
+ [tool.hatch.build.targets.wheel]
60
+ only-include = ["stac_fastapi"]
@@ -0,0 +1,4 @@
1
+ [pytest]
2
+ testpaths = tests
3
+ addopts = -sv
4
+ asyncio_mode = auto
@@ -3,6 +3,8 @@
3
3
  import abc
4
4
  from typing import Any, Dict, Iterable, List, Optional, Tuple
5
5
 
6
+ from stac_pydantic.shared import BBox
7
+
6
8
 
7
9
  class BaseDatabaseLogic(abc.ABC):
8
10
  """
@@ -19,7 +21,12 @@ class BaseDatabaseLogic(abc.ABC):
19
21
  limit: int,
20
22
  request: Any = None,
21
23
  sort: Optional[List[Dict[str, Any]]] = None,
22
- ) -> Tuple[List[Dict[str, Any]], Optional[str]]:
24
+ bbox: Optional[BBox] = None,
25
+ q: Optional[List[str]] = None,
26
+ filter: Optional[Dict[str, Any]] = None,
27
+ query: Optional[Dict[str, Dict[str, Any]]] = None,
28
+ datetime: Optional[str] = None,
29
+ ) -> Tuple[List[Dict[str, Any]], Optional[str], Optional[int]]:
23
30
  """Retrieve a list of collections from the database, supporting pagination.
24
31
 
25
32
  Args:
@@ -27,9 +34,14 @@ class BaseDatabaseLogic(abc.ABC):
27
34
  limit (int): The number of results to return.
28
35
  request (Any, optional): The FastAPI request object. Defaults to None.
29
36
  sort (Optional[List[Dict[str, Any]]], optional): Optional sort parameter. Defaults to None.
37
+ bbox (Optional[BBox], optional): Bounding box to filter collections by spatial extent. Defaults to None.
38
+ q (Optional[List[str]], optional): Free text search terms. Defaults to None.
39
+ filter (Optional[Dict[str, Any]], optional): Structured query in CQL2 format. Defaults to None.
40
+ query (Optional[Dict[str, Dict[str, Any]]], optional): Query extension parameters. Defaults to None.
41
+ datetime (Optional[str], optional): Temporal filter. Defaults to None.
30
42
 
31
43
  Returns:
32
- A tuple of (collections, next pagination token if any).
44
+ A tuple of (collections, next pagination token if any, optional count).
33
45
  """
34
46
  pass
35
47
 
@@ -24,9 +24,10 @@ from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
24
24
  from stac_fastapi.core.base_settings import ApiBaseSettings
25
25
  from stac_fastapi.core.datetime_utils import format_datetime_range
26
26
  from stac_fastapi.core.models.links import PagingLinks
27
+ from stac_fastapi.core.redis_utils import redis_pagination_links
27
28
  from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
28
29
  from stac_fastapi.core.session import Session
29
- from stac_fastapi.core.utilities import filter_fields
30
+ from stac_fastapi.core.utilities import filter_fields, get_bool_env
30
31
  from stac_fastapi.extensions.core.transaction import AsyncBaseTransactionsClient
31
32
  from stac_fastapi.extensions.core.transaction.request import (
32
33
  PartialCollection,
@@ -201,17 +202,6 @@ class CoreClient(AsyncBaseCoreClient):
201
202
  ]
202
203
  )
203
204
 
204
- collections = await self.all_collections(request=kwargs["request"])
205
- for collection in collections["collections"]:
206
- landing_page["links"].append(
207
- {
208
- "rel": Relations.child.value,
209
- "type": MimeTypes.json.value,
210
- "title": collection.get("title") or collection.get("id"),
211
- "href": urljoin(base_url, f"collections/{collection['id']}"),
212
- }
213
- )
214
-
215
205
  # Add OpenAPI URL
216
206
  landing_page["links"].append(
217
207
  {
@@ -241,6 +231,7 @@ class CoreClient(AsyncBaseCoreClient):
241
231
  async def all_collections(
242
232
  self,
243
233
  limit: Optional[int] = None,
234
+ bbox: Optional[BBox] = None,
244
235
  datetime: Optional[str] = None,
245
236
  fields: Optional[List[str]] = None,
246
237
  sortby: Optional[Union[str, List[str]]] = None,
@@ -255,49 +246,50 @@ class CoreClient(AsyncBaseCoreClient):
255
246
  """Read all collections from the database.
256
247
 
257
248
  Args:
258
- datetime (Optional[str]): Filter collections by datetime range.
259
249
  limit (Optional[int]): Maximum number of collections to return.
250
+ bbox (Optional[BBox]): Bounding box to filter collections by spatial extent.
251
+ datetime (Optional[str]): Filter collections by datetime range.
260
252
  fields (Optional[List[str]]): Fields to include or exclude from the results.
261
- sortby (Optional[str]): Sorting options for the results.
253
+ sortby (Optional[Union[str, List[str]]]): Sorting options for the results.
262
254
  filter_expr (Optional[str]): Structured filter expression in CQL2 JSON or CQL2-text format.
263
- query (Optional[str]): Legacy query parameter (deprecated).
264
255
  filter_lang (Optional[str]): Must be 'cql2-json' or 'cql2-text' if specified, other values will result in an error.
265
256
  q (Optional[Union[str, List[str]]]): Free text search terms.
257
+ query (Optional[str]): Legacy query parameter (deprecated).
258
+ request (Request): FastAPI Request object.
259
+ token (Optional[str]): Pagination token for retrieving the next page of results.
266
260
  **kwargs: Keyword arguments from the request.
267
261
 
268
262
  Returns:
269
263
  A Collections object containing all the collections in the database and links to various resources.
270
264
  """
271
265
  base_url = str(request.base_url)
266
+ redis_enable = get_bool_env("REDIS_ENABLE", default=False)
272
267
 
273
- # Get the global limit from environment variable
274
- global_limit = None
275
- env_limit = os.getenv("STAC_ITEM_LIMIT")
276
- if env_limit:
277
- try:
278
- global_limit = int(env_limit)
279
- except ValueError:
280
- # Handle invalid integer in environment variable
281
- pass
282
-
283
- # Apply global limit if it exists
284
- if global_limit is not None:
285
- # If a limit was provided, use the smaller of the two
286
- if limit is not None:
287
- limit = min(limit, global_limit)
288
- else:
289
- limit = global_limit
268
+ global_max_limit = (
269
+ int(os.getenv("STAC_GLOBAL_COLLECTION_MAX_LIMIT"))
270
+ if os.getenv("STAC_GLOBAL_COLLECTION_MAX_LIMIT")
271
+ else None
272
+ )
273
+ query_limit = request.query_params.get("limit")
274
+ default_limit = int(os.getenv("STAC_DEFAULT_COLLECTION_LIMIT", 300))
275
+
276
+ body_limit = None
277
+ try:
278
+ if request.method == "POST" and request.body():
279
+ body_data = await request.json()
280
+ body_limit = body_data.get("limit")
281
+ except Exception:
282
+ pass
283
+
284
+ if body_limit is not None:
285
+ limit = int(body_limit)
286
+ elif query_limit:
287
+ limit = int(query_limit)
290
288
  else:
291
- # No global limit, use provided limit or default
292
- if limit is None:
293
- query_limit = request.query_params.get("limit")
294
- if query_limit:
295
- try:
296
- limit = int(query_limit)
297
- except ValueError:
298
- limit = 10
299
- else:
300
- limit = 10
289
+ limit = default_limit
290
+
291
+ if global_max_limit is not None:
292
+ limit = min(limit, global_max_limit)
301
293
 
302
294
  # Get token from query params only if not already provided (for GET requests)
303
295
  if token is None:
@@ -401,6 +393,7 @@ class CoreClient(AsyncBaseCoreClient):
401
393
  limit=limit,
402
394
  request=request,
403
395
  sort=sort,
396
+ bbox=bbox,
404
397
  q=q_list,
405
398
  filter=parsed_filter,
406
399
  query=parsed_query,
@@ -426,6 +419,14 @@ class CoreClient(AsyncBaseCoreClient):
426
419
  },
427
420
  ]
428
421
 
422
+ if redis_enable:
423
+ await redis_pagination_links(
424
+ current_url=str(request.url),
425
+ token=token,
426
+ next_token=next_token,
427
+ links=links,
428
+ )
429
+
429
430
  if next_token:
430
431
  next_link = PagingLinks(next=next_token, request=request).link_next()
431
432
  links.append(next_link)
@@ -502,6 +503,7 @@ class CoreClient(AsyncBaseCoreClient):
502
503
  # Pass all parameters from search_request to all_collections
503
504
  return await self.all_collections(
504
505
  limit=search_request.limit if hasattr(search_request, "limit") else None,
506
+ bbox=search_request.bbox if hasattr(search_request, "bbox") else None,
505
507
  datetime=search_request.datetime
506
508
  if hasattr(search_request, "datetime")
507
509
  else None,
@@ -569,7 +571,7 @@ class CoreClient(AsyncBaseCoreClient):
569
571
  request (Request): FastAPI Request object.
570
572
  bbox (Optional[BBox]): Optional bounding box filter.
571
573
  datetime (Optional[str]): Optional datetime or interval filter.
572
- limit (Optional[int]): Optional page size. Defaults to env ``STAC_ITEM_LIMIT`` when unset.
574
+ limit (Optional[int]): Optional page size. Defaults to env `STAC_DEFAULT_ITEM_LIMIT` when unset.
573
575
  sortby (Optional[str]): Optional sort specification. Accepts repeated values
574
576
  like ``sortby=-properties.datetime`` or ``sortby=+id``. Bare fields (e.g. ``sortby=id``)
575
577
  imply ascending order.
@@ -660,15 +662,12 @@ class CoreClient(AsyncBaseCoreClient):
660
662
  q (Optional[List[str]]): Free text query to filter the results.
661
663
  intersects (Optional[str]): GeoJSON geometry to search in.
662
664
  kwargs: Additional parameters to be passed to the API.
663
-
664
665
  Returns:
665
666
  ItemCollection: Collection of `Item` objects representing the search results.
666
667
 
667
668
  Raises:
668
669
  HTTPException: If any error occurs while searching the catalog.
669
670
  """
670
- limit = int(request.query_params.get("limit", os.getenv("STAC_ITEM_LIMIT", 10)))
671
-
672
671
  base_args = {
673
672
  "collections": collections,
674
673
  "ids": ids,
@@ -743,9 +742,37 @@ class CoreClient(AsyncBaseCoreClient):
743
742
  Raises:
744
743
  HTTPException: If there is an error with the cql2_json filter.
745
744
  """
746
- base_url = str(request.base_url)
745
+ global_max_limit = (
746
+ int(os.getenv("STAC_GLOBAL_ITEM_MAX_LIMIT"))
747
+ if os.getenv("STAC_GLOBAL_ITEM_MAX_LIMIT")
748
+ else None
749
+ )
750
+ query_limit = request.query_params.get("limit")
751
+ default_limit = int(os.getenv("STAC_DEFAULT_ITEM_LIMIT", 10))
747
752
 
753
+ body_limit = None
754
+ try:
755
+ if request.method == "POST" and request.body():
756
+ body_data = await request.json()
757
+ body_limit = body_data.get("limit")
758
+ except Exception:
759
+ pass
760
+
761
+ if body_limit is not None:
762
+ limit = int(body_limit)
763
+ elif query_limit:
764
+ limit = int(query_limit)
765
+ else:
766
+ limit = default_limit
767
+
768
+ if global_max_limit:
769
+ limit = min(limit, global_max_limit)
770
+
771
+ search_request.limit = limit
772
+
773
+ base_url = str(request.base_url)
748
774
  search = self.database.make_search()
775
+ redis_enable = get_bool_env("REDIS_ENABLE", default=False)
749
776
 
750
777
  if search_request.ids:
751
778
  search = self.database.apply_ids_filter(
@@ -819,7 +846,6 @@ class CoreClient(AsyncBaseCoreClient):
819
846
  if hasattr(search_request, "sortby") and getattr(search_request, "sortby"):
820
847
  sort = self.database.populate_sort(getattr(search_request, "sortby"))
821
848
 
822
- limit = 10
823
849
  if search_request.limit:
824
850
  limit = search_request.limit
825
851
 
@@ -850,6 +876,34 @@ class CoreClient(AsyncBaseCoreClient):
850
876
  ]
851
877
  links = await PagingLinks(request=request, next=next_token).get_links()
852
878
 
879
+ collection_links = []
880
+ # Add "collection" and "parent" rels only for /collections/{collection_id}/items
881
+ if search_request.collections and "/items" in str(request.url):
882
+ for collection_id in search_request.collections:
883
+ collection_links.extend(
884
+ [
885
+ {
886
+ "rel": "collection",
887
+ "type": "application/json",
888
+ "href": urljoin(base_url, f"collections/{collection_id}"),
889
+ },
890
+ {
891
+ "rel": "parent",
892
+ "type": "application/json",
893
+ "href": urljoin(base_url, f"collections/{collection_id}"),
894
+ },
895
+ ]
896
+ )
897
+ links.extend(collection_links)
898
+
899
+ if redis_enable:
900
+ await redis_pagination_links(
901
+ current_url=str(request.url),
902
+ token=token_param,
903
+ next_token=next_token,
904
+ links=links,
905
+ )
906
+
853
907
  return stac_types.ItemCollection(
854
908
  type="FeatureCollection",
855
909
  features=items,