|
3 | 3 | import os |
4 | 4 | from typing import Optional |
5 | 5 |
|
6 | | -from fastapi import FastAPI, HTTPException, Request, status |
| 6 | +from datetime import datetime |
| 7 | + |
| 8 | +from fastapi import FastAPI, HTTPException, Request, status, Query |
7 | 9 | from fastapi.middleware.cors import CORSMiddleware |
8 | 10 | from starlette.middleware.authentication import AuthenticationMiddleware |
9 | 11 | from starlette.authentication import requires |
|
18 | 20 |
|
19 | 21 | from geoquery.geoquery import GeoQuery |
20 | 22 | from geoquery.task import TaskList |
| 23 | +from geoquery.geoquery import GeoQuery |
21 | 24 |
|
22 | 25 | from utils.api_logging import get_dds_logger |
23 | 26 | import exceptions as exc |
|
32 | 35 | from const import venv, tags |
33 | 36 | from auth import scopes |
34 | 37 |
|
| 38 | +def map_to_geoquery( |
| 39 | + variables: list[str], |
| 40 | + format: str, |
| 41 | + bbox: str | None = None, # minx, miny, maxx, maxy (minlon, minlat, maxlon, maxlat) |
| 42 | + time: datetime | None = None, |
| 43 | + **format_kwargs |
| 44 | +) -> GeoQuery: |
| 45 | + |
| 46 | + bbox_ = [float(x) for x in bbox.split(',')] |
| 47 | + area = { 'west': bbox_[0], 'south': bbox_[1], 'east': bbox_[2], 'north': bbox_[3], } |
| 48 | + time_ = { 'year': time.year, 'month': time.month, 'day': time.day, 'hour': time.hour} |
| 49 | + query = GeoQuery(variable=variables, time=time_, area=area, |
| 50 | + format_args=format_kwargs, format=format) |
| 51 | + return query |
| 52 | + |
35 | 53 | logger = get_dds_logger(__name__) |
36 | 54 |
|
37 | 55 | # ======== JSON encoders extension ========= # |
@@ -155,6 +173,100 @@ async def get_product_details( |
155 | 173 | except exc.BaseDDSException as err: |
156 | 174 | raise err.wrap_around_http_exception() from err |
157 | 175 |
|
| 176 | +@app.get("/datasets/{dataset_id}/{product_id}/map", tags=[tags.DATASET]) |
| 177 | +@timer( |
| 178 | + app.state.api_request_duration_seconds, |
| 179 | + labels={"route": "GET /datasets/{dataset_id}/{product_id}"}, |
| 180 | +) |
| 181 | +async def get_map( |
| 182 | + request: Request, |
| 183 | + dataset_id: str, |
| 184 | + product_id: str, |
| 185 | +# OGC WMS parameters |
| 186 | + width: int, |
| 187 | + height: int, |
| 188 | + layers: str | None = None, |
| 189 | + format: str | None = 'png', |
| 190 | + time: datetime | None = None, |
| 191 | + transparent: bool | None = 'true', |
| 192 | + bgcolor: str | None = 'FFFFFF', |
| 193 | + bbox: str | None = None, # minx, miny, maxx, maxy (minlon, minlat, maxlon, maxlat) |
| 194 | + crs: str | None = None, |
| 195 | +# OGC map parameters |
| 196 | + # subset: str | None = None, |
| 197 | + # subset_crs: str | None = Query(..., alias="subset-crs"), |
| 198 | + # bbox_crs: str | None = Query(..., alias="bbox-crs"), |
| 199 | +): |
| 200 | + |
| 201 | + app.state.api_http_requests_total.inc( |
| 202 | + {"route": "GET /datasets/{dataset_id}/{product_id}/map"} |
| 203 | + ) |
| 204 | + # query should be the OGC query |
| 205 | + # map OGC parameters to GeoQuery |
| 206 | + # variable: Optional[Union[str, List[str]]] |
| 207 | + # time: Optional[Union[Dict[str, str], Dict[str, List[str]]]] |
| 208 | + # area: Optional[Dict[str, float]] |
| 209 | + # location: Optional[Dict[str, Union[float, List[float]]]] |
| 210 | + # vertical: Optional[Union[float, List[float], Dict[str, float]]] |
| 211 | + # filters: Optional[Dict] |
| 212 | + # format: Optional[str] |
| 213 | + query = map_to_geoquery(variables=layers, bbox=bbox, time=time, |
| 214 | + format="png", width=width, height=height, |
| 215 | + transparent=transparent, bgcolor=bgcolor) |
| 216 | + try: |
| 217 | + return dataset_handler.sync_query( |
| 218 | + user_id=request.user.id, |
| 219 | + dataset_id=dataset_id, |
| 220 | + product_id=product_id, |
| 221 | + query=query |
| 222 | + ) |
| 223 | + except exc.BaseDDSException as err: |
| 224 | + raise err.wrap_around_http_exception() from err |
| 225 | + |
| 226 | +@app.get("/datasets/{dataset_id}/{product_id}/items/{feature_id}", tags=[tags.DATASET]) |
| 227 | +@timer( |
| 228 | + app.state.api_request_duration_seconds, |
| 229 | + labels={"route": "GET /datasets/{dataset_id}/{product_id}/items/{feature_id}"}, |
| 230 | +) |
| 231 | +async def get_feature( |
| 232 | + request: Request, |
| 233 | + dataset_id: str, |
| 234 | + product_id: str, |
| 235 | + feature_id: str, |
| 236 | +# OGC feature parameters |
| 237 | + time: datetime | None = None, |
| 238 | + bbox: str | None = None, # minx, miny, maxx, maxy (minlon, minlat, maxlon, maxlat) |
| 239 | + crs: str | None = None, |
| 240 | +# OGC map parameters |
| 241 | + # subset: str | None = None, |
| 242 | + # subset_crs: str | None = Query(..., alias="subset-crs"), |
| 243 | + # bbox_crs: str | None = Query(..., alias="bbox-crs"), |
| 244 | +): |
| 245 | + |
| 246 | + app.state.api_http_requests_total.inc( |
| 247 | + {"route": "GET /datasets/{dataset_id}/{product_id}/items/{feature_id}"} |
| 248 | + ) |
| 249 | + # query should be the OGC query |
| 250 | + # feature OGC parameters to GeoQuery |
| 251 | + # variable: Optional[Union[str, List[str]]] |
| 252 | + # time: Optional[Union[Dict[str, str], Dict[str, List[str]]]] |
| 253 | + # area: Optional[Dict[str, float]] |
| 254 | + # location: Optional[Dict[str, Union[float, List[float]]]] |
| 255 | + # vertical: Optional[Union[float, List[float], Dict[str, float]]] |
| 256 | + # filters: Optional[Dict] |
| 257 | + # format: Optional[str] |
| 258 | + |
| 259 | + query = map_to_geoquery(variables=[feature_id], bbox=bbox, time=time, |
| 260 | + format="geojson") |
| 261 | + try: |
| 262 | + return dataset_handler.sync_query( |
| 263 | + user_id=request.user.id, |
| 264 | + dataset_id=dataset_id, |
| 265 | + product_id=product_id, |
| 266 | + query=query |
| 267 | + ) |
| 268 | + except exc.BaseDDSException as err: |
| 269 | + raise err.wrap_around_http_exception() from err |
158 | 270 |
|
159 | 271 | @app.get("/datasets/{dataset_id}/{product_id}/metadata", tags=[tags.DATASET]) |
160 | 272 | @timer( |
@@ -222,7 +334,7 @@ async def query( |
222 | 334 | {"route": "POST /datasets/{dataset_id}/{product_id}/execute"} |
223 | 335 | ) |
224 | 336 | try: |
225 | | - return dataset_handler.query( |
| 337 | + return dataset_handler.async_query( |
226 | 338 | user_id=request.user.id, |
227 | 339 | dataset_id=dataset_id, |
228 | 340 | product_id=product_id, |
|
0 commit comments