stac-fastapi.core 3.1.0__tar.gz → 3.2.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.
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/PKG-INFO +5 -14
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/README.md +5 -1
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/setup.py +1 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/aggregation.py +36 -1
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/models/links.py +8 -0
- stac-fastapi.core-3.2.0/stac_fastapi/core/rate_limit.py +44 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/version.py +1 -1
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/PKG-INFO +5 -14
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/SOURCES.txt +1 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/requires.txt +1 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/top_level.txt +0 -1
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/setup.cfg +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/__init__.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/base_database_logic.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/base_settings.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/basic_auth.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/core.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/datetime_utils.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/__init__.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/fields.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/filter.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/query.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/models/__init__.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/models/search.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/route_dependencies.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/serializers.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/session.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/utilities.py +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/dependency_links.txt +0 -0
- {stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/not-zip-safe +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: stac-fastapi.core
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
|
|
5
5
|
Home-page: https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
|
|
6
6
|
License: MIT
|
|
@@ -15,19 +15,6 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: fastapi-slim
|
|
19
|
-
Requires-Dist: attrs>=23.2.0
|
|
20
|
-
Requires-Dist: pydantic[dotenv]
|
|
21
|
-
Requires-Dist: stac_pydantic>=3
|
|
22
|
-
Requires-Dist: stac-fastapi.types==3.0.0
|
|
23
|
-
Requires-Dist: stac-fastapi.api==3.0.0
|
|
24
|
-
Requires-Dist: stac-fastapi.extensions==3.0.0
|
|
25
|
-
Requires-Dist: orjson
|
|
26
|
-
Requires-Dist: overrides
|
|
27
|
-
Requires-Dist: geojson-pydantic
|
|
28
|
-
Requires-Dist: pygeofilter==0.2.1
|
|
29
|
-
Requires-Dist: typing_extensions==4.8.0
|
|
30
|
-
Requires-Dist: jsonschema
|
|
31
18
|
|
|
32
19
|
# stac-fastapi-elasticsearch-opensearch (sfeos)
|
|
33
20
|
|
|
@@ -415,3 +402,7 @@ Available aggregations are:
|
|
|
415
402
|
- geometry_geotile_grid_frequency ([geotile grid](https://opensearch.org/docs/latest/aggregations/bucket/geotile-grid/) on Item.geometry)
|
|
416
403
|
|
|
417
404
|
Support for additional fields and new aggregations can be added in the associated `database_logic.py` file.
|
|
405
|
+
|
|
406
|
+
## Rate Limiting
|
|
407
|
+
|
|
408
|
+
Rate limiting is an optional security feature that controls API request frequency on a remote address basis. It's enabled by setting the `STAC_FASTAPI_RATE_LIMIT` environment variable, e.g., `500/minute`. This limits each client to 500 requests per minute, helping prevent abuse and maintain API stability. Implementation examples are available in the [examples/rate_limit](examples/rate_limit) directory.
|
|
@@ -383,4 +383,8 @@ Available aggregations are:
|
|
|
383
383
|
- geometry_geohash_grid_frequency ([geohash grid](https://opensearch.org/docs/latest/aggregations/bucket/geohash-grid/) on Item.geometry)
|
|
384
384
|
- geometry_geotile_grid_frequency ([geotile grid](https://opensearch.org/docs/latest/aggregations/bucket/geotile-grid/) on Item.geometry)
|
|
385
385
|
|
|
386
|
-
Support for additional fields and new aggregations can be added in the associated `database_logic.py` file.
|
|
386
|
+
Support for additional fields and new aggregations can be added in the associated `database_logic.py` file.
|
|
387
|
+
|
|
388
|
+
## Rate Limiting
|
|
389
|
+
|
|
390
|
+
Rate limiting is an optional security feature that controls API request frequency on a remote address basis. It's enabled by setting the `STAC_FASTAPI_RATE_LIMIT` environment variable, e.g., `500/minute`. This limits each client to 500 requests per minute, helping prevent abuse and maintain API stability. Implementation examples are available in the [examples/rate_limit](examples/rate_limit) directory.
|
{stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/aggregation.py
RENAMED
|
@@ -50,6 +50,7 @@ class EsAggregationExtensionGetRequest(
|
|
|
50
50
|
centroid_geotile_grid_frequency_precision: Optional[int] = attr.ib(default=None)
|
|
51
51
|
geometry_geohash_grid_frequency_precision: Optional[int] = attr.ib(default=None)
|
|
52
52
|
geometry_geotile_grid_frequency_precision: Optional[int] = attr.ib(default=None)
|
|
53
|
+
datetime_frequency_interval: Optional[str] = attr.ib(default=None)
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
class EsAggregationExtensionPostRequest(
|
|
@@ -62,6 +63,7 @@ class EsAggregationExtensionPostRequest(
|
|
|
62
63
|
centroid_geotile_grid_frequency_precision: Optional[int] = None
|
|
63
64
|
geometry_geohash_grid_frequency_precision: Optional[int] = None
|
|
64
65
|
geometry_geotile_grid_frequency_precision: Optional[int] = None
|
|
66
|
+
datetime_frequency_interval: Optional[str] = None
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
@attr.s
|
|
@@ -124,6 +126,8 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
124
126
|
MAX_GEOHASH_PRECISION = 12
|
|
125
127
|
MAX_GEOHEX_PRECISION = 15
|
|
126
128
|
MAX_GEOTILE_PRECISION = 29
|
|
129
|
+
SUPPORTED_DATETIME_INTERVAL = {"day", "month", "year"}
|
|
130
|
+
DEFAULT_DATETIME_INTERVAL = "month"
|
|
127
131
|
|
|
128
132
|
async def get_aggregations(self, collection_id: Optional[str] = None, **kwargs):
|
|
129
133
|
"""Get the available aggregations for a catalog or collection defined in the STAC JSON. If no aggregations, default aggregations are used."""
|
|
@@ -143,7 +147,7 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
143
147
|
{
|
|
144
148
|
"rel": "self",
|
|
145
149
|
"type": "application/json",
|
|
146
|
-
"href": urljoin(collection_endpoint, "aggregations"),
|
|
150
|
+
"href": urljoin(collection_endpoint + "/", "aggregations"),
|
|
147
151
|
},
|
|
148
152
|
]
|
|
149
153
|
)
|
|
@@ -182,6 +186,30 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
182
186
|
else:
|
|
183
187
|
return min_value
|
|
184
188
|
|
|
189
|
+
def extract_date_histogram_interval(self, value: Optional[str]) -> str:
|
|
190
|
+
"""
|
|
191
|
+
Ensure that the interval for the date histogram is valid. If no value is provided, the default will be returned.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
value: value entered by the user
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
string containing the date histogram interval to use.
|
|
198
|
+
|
|
199
|
+
Raises:
|
|
200
|
+
HTTPException: if the supplied value is not in the supported intervals
|
|
201
|
+
"""
|
|
202
|
+
if value is not None:
|
|
203
|
+
if value not in self.SUPPORTED_DATETIME_INTERVAL:
|
|
204
|
+
raise HTTPException(
|
|
205
|
+
status_code=400,
|
|
206
|
+
detail=f"Invalid datetime interval. Must be one of {self.SUPPORTED_DATETIME_INTERVAL}",
|
|
207
|
+
)
|
|
208
|
+
else:
|
|
209
|
+
return value
|
|
210
|
+
else:
|
|
211
|
+
return self.DEFAULT_DATETIME_INTERVAL
|
|
212
|
+
|
|
185
213
|
@staticmethod
|
|
186
214
|
def _return_date(
|
|
187
215
|
interval: Optional[Union[DateTimeType, str]]
|
|
@@ -319,6 +347,7 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
319
347
|
centroid_geotile_grid_frequency_precision: Optional[int] = None,
|
|
320
348
|
geometry_geohash_grid_frequency_precision: Optional[int] = None,
|
|
321
349
|
geometry_geotile_grid_frequency_precision: Optional[int] = None,
|
|
350
|
+
datetime_frequency_interval: Optional[str] = None,
|
|
322
351
|
**kwargs,
|
|
323
352
|
) -> Union[Dict, Exception]:
|
|
324
353
|
"""Get aggregations from the database."""
|
|
@@ -339,6 +368,7 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
339
368
|
"centroid_geotile_grid_frequency_precision": centroid_geotile_grid_frequency_precision,
|
|
340
369
|
"geometry_geohash_grid_frequency_precision": geometry_geohash_grid_frequency_precision,
|
|
341
370
|
"geometry_geotile_grid_frequency_precision": geometry_geotile_grid_frequency_precision,
|
|
371
|
+
"datetime_frequency_interval": datetime_frequency_interval,
|
|
342
372
|
}
|
|
343
373
|
|
|
344
374
|
if collection_id:
|
|
@@ -475,6 +505,10 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
475
505
|
self.MAX_GEOTILE_PRECISION,
|
|
476
506
|
)
|
|
477
507
|
|
|
508
|
+
datetime_frequency_interval = self.extract_date_histogram_interval(
|
|
509
|
+
aggregate_request.datetime_frequency_interval,
|
|
510
|
+
)
|
|
511
|
+
|
|
478
512
|
try:
|
|
479
513
|
db_response = await self.database.aggregate(
|
|
480
514
|
collections,
|
|
@@ -485,6 +519,7 @@ class EsAsyncAggregationClient(AsyncBaseAggregationClient):
|
|
|
485
519
|
centroid_geotile_grid_precision,
|
|
486
520
|
geometry_geohash_grid_precision,
|
|
487
521
|
geometry_geotile_grid_precision,
|
|
522
|
+
datetime_frequency_interval,
|
|
488
523
|
)
|
|
489
524
|
except Exception as error:
|
|
490
525
|
if not isinstance(error, IndexError):
|
|
@@ -114,6 +114,14 @@ class CollectionLinks(BaseLinks):
|
|
|
114
114
|
collection_id: str = attr.ib()
|
|
115
115
|
extensions: List[str] = attr.ib(default=attr.Factory(list))
|
|
116
116
|
|
|
117
|
+
def link_self(self) -> Dict:
|
|
118
|
+
"""Return the self link."""
|
|
119
|
+
return dict(
|
|
120
|
+
rel=Relations.self.value,
|
|
121
|
+
type=MimeTypes.json.value,
|
|
122
|
+
href=urljoin(self.base_url, f"collections/{self.collection_id}"),
|
|
123
|
+
)
|
|
124
|
+
|
|
117
125
|
def link_parent(self) -> Dict[str, Any]:
|
|
118
126
|
"""Create the `parent` link."""
|
|
119
127
|
return dict(rel=Relations.parent, type=MimeTypes.json.value, href=self.base_url)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Rate limiting middleware."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from fastapi import FastAPI, Request
|
|
8
|
+
from slowapi import Limiter, _rate_limit_exceeded_handler
|
|
9
|
+
from slowapi.errors import RateLimitExceeded
|
|
10
|
+
from slowapi.middleware import SlowAPIMiddleware
|
|
11
|
+
from slowapi.util import get_remote_address
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_limiter(key_func=get_remote_address):
|
|
17
|
+
"""Create and return a Limiter instance for rate limiting."""
|
|
18
|
+
return Limiter(key_func=key_func)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def setup_rate_limit(
|
|
22
|
+
app: FastAPI, rate_limit: Optional[str] = None, key_func=get_remote_address
|
|
23
|
+
):
|
|
24
|
+
"""Set up rate limiting middleware."""
|
|
25
|
+
RATE_LIMIT = rate_limit or os.getenv("STAC_FASTAPI_RATE_LIMIT")
|
|
26
|
+
|
|
27
|
+
if not RATE_LIMIT:
|
|
28
|
+
logger.info("Rate limiting is disabled")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
logger.info(f"Setting up rate limit with RATE_LIMIT={RATE_LIMIT}")
|
|
32
|
+
|
|
33
|
+
limiter = get_limiter(key_func)
|
|
34
|
+
app.state.limiter = limiter
|
|
35
|
+
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
36
|
+
app.add_middleware(SlowAPIMiddleware)
|
|
37
|
+
|
|
38
|
+
@app.middleware("http")
|
|
39
|
+
@limiter.limit(RATE_LIMIT)
|
|
40
|
+
async def rate_limit_middleware(request: Request, call_next):
|
|
41
|
+
response = await call_next(request)
|
|
42
|
+
return response
|
|
43
|
+
|
|
44
|
+
logger.info("Rate limit setup complete")
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""library version."""
|
|
2
|
-
__version__ = "3.
|
|
2
|
+
__version__ = "3.2.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: stac-fastapi.core
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
|
|
5
5
|
Home-page: https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
|
|
6
6
|
License: MIT
|
|
@@ -15,19 +15,6 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
|
-
Requires-Dist: fastapi-slim
|
|
19
|
-
Requires-Dist: attrs>=23.2.0
|
|
20
|
-
Requires-Dist: pydantic[dotenv]
|
|
21
|
-
Requires-Dist: stac_pydantic>=3
|
|
22
|
-
Requires-Dist: stac-fastapi.types==3.0.0
|
|
23
|
-
Requires-Dist: stac-fastapi.api==3.0.0
|
|
24
|
-
Requires-Dist: stac-fastapi.extensions==3.0.0
|
|
25
|
-
Requires-Dist: orjson
|
|
26
|
-
Requires-Dist: overrides
|
|
27
|
-
Requires-Dist: geojson-pydantic
|
|
28
|
-
Requires-Dist: pygeofilter==0.2.1
|
|
29
|
-
Requires-Dist: typing_extensions==4.8.0
|
|
30
|
-
Requires-Dist: jsonschema
|
|
31
18
|
|
|
32
19
|
# stac-fastapi-elasticsearch-opensearch (sfeos)
|
|
33
20
|
|
|
@@ -415,3 +402,7 @@ Available aggregations are:
|
|
|
415
402
|
- geometry_geotile_grid_frequency ([geotile grid](https://opensearch.org/docs/latest/aggregations/bucket/geotile-grid/) on Item.geometry)
|
|
416
403
|
|
|
417
404
|
Support for additional fields and new aggregations can be added in the associated `database_logic.py` file.
|
|
405
|
+
|
|
406
|
+
## Rate Limiting
|
|
407
|
+
|
|
408
|
+
Rate limiting is an optional security feature that controls API request frequency on a remote address basis. It's enabled by setting the `STAC_FASTAPI_RATE_LIMIT` environment variable, e.g., `500/minute`. This limits each client to 500 requests per minute, helping prevent abuse and maintain API stability. Implementation examples are available in the [examples/rate_limit](examples/rate_limit) directory.
|
|
@@ -13,6 +13,7 @@ stac_fastapi/core/base_settings.py
|
|
|
13
13
|
stac_fastapi/core/basic_auth.py
|
|
14
14
|
stac_fastapi/core/core.py
|
|
15
15
|
stac_fastapi/core/datetime_utils.py
|
|
16
|
+
stac_fastapi/core/rate_limit.py
|
|
16
17
|
stac_fastapi/core/route_dependencies.py
|
|
17
18
|
stac_fastapi/core/serializers.py
|
|
18
19
|
stac_fastapi/core/session.py
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/base_database_logic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi/core/extensions/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stac_fastapi_core-3.1.0 → stac-fastapi.core-3.2.0}/stac_fastapi.core.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|