EDR Router#

The OGC Environmental Data Retrieval API is designed to be a common web mapping focused method for querying data.

In restful-grids/xpublish/edr_router.py, we’ve implemented edr_router which currently provides an EDR position endpoint. This endpoint is especially useful for querying a time series from a gridded dataset.

The default response for EDR endpoints is CoverageJSON, but we’ve also decided to support NetCDF responses if f=nc is added to the query parameters, or CSV with f=csv.

Setting up the router#

The edr_router expects datasets that have CF conventions attributes that cf-xarray can read. Specifically it’s looking for attributes that the ds.cf.axes can find X and Y axes (Z and T will also be used if found).

If a dataset doesn’t have full CF attributes, you can set them with ds[X_COORD].attrs["axis"] = "X" and similar for the other axes.

Then you can import and include edr_router when instantiating xpublish.Rest or subclass. We suggest including a prefix for routers to avoid conflicts, similar to:

rest = xpublish.Rest(
    DATASETS_DICT,
    routers=[
        (base_router, {"tags": ["info"]}),
        (edr_router, {"tags": ["edr"], "prefix": "/edr"}),
        (zarr_router, {"tags": ["zarr"], "prefix": "/zarr"}),
    ]
)

At this point you will get an EDR endpoint at /datasets/{dataset_id}/edr/position (or /edr/position if you only have a single dataset).

Making a request#

The minimum path and query params you need for a request is a dataset_id (see /datasets/) and a Well Known Text point for the coords query string.

The endpoint will try to find the nearest values to the point.

parameter-name#

We are also going to add a parameter-name to keep this somewhat reasonable, though that is not necessary and the endpoint will respond with all variables.

Multiple parameters (variables) can also be given by comma seperating them, and due to the magic of cf-xarray, CF standard names can also be used and will return the associated variables. (in this case &parameter-name=sea_surface_wave_significant_height would return the hs variable.

import requests
r = requests.get(
    "http://0.0.0.0:9005/datasets/ww3/edr/position"
    "?coords=POINT(-69.35 43.72)"
    "&parameter-name=sea_surface_wave_significant_height"
)
r.json()
{'type': 'Coverage',
 'domain': {'type': 'Domain',
  'domainType': 'Grid',
  'axes': {'t': {'values': ['2022-04-11T12:00:00',
     '2022-04-11T12:59:59',
     '2022-04-11T14:00:00',
     '2022-04-11T15:00:00',
     '2022-04-11T15:59:59',
     '2022-04-11T17:00:00',
     '2022-04-11T18:00:00',
     '2022-04-11T18:59:59',
     '2022-04-11T20:00:00',
     '2022-04-11T21:00:00',
     '2022-04-11T21:59:59',
     '2022-04-11T23:00:00',
     '2022-04-12T00:00:00',
     '2022-04-12T00:59:59',
     '2022-04-12T02:00:00',
     '2022-04-12T03:00:00',
     '2022-04-12T03:59:59',
     '2022-04-12T05:00:00',
     '2022-04-12T06:00:00',
     '2022-04-12T06:59:59',
     '2022-04-12T08:00:00',
     '2022-04-12T09:00:00',
     '2022-04-12T09:59:59',
     '2022-04-12T11:00:00',
     '2022-04-12T12:00:00',
     '2022-04-12T12:59:59',
     '2022-04-12T14:00:00',
     '2022-04-12T15:00:00',
     '2022-04-12T15:59:59',
     '2022-04-12T17:00:00',
     '2022-04-12T18:00:00',
     '2022-04-12T18:59:59',
     '2022-04-12T20:00:00',
     '2022-04-12T21:00:00',
     '2022-04-12T21:59:59',
     '2022-04-12T23:00:00',
     '2022-04-13T00:00:00',
     '2022-04-13T00:59:59',
     '2022-04-13T02:00:00',
     '2022-04-13T03:00:00',
     '2022-04-13T03:59:59',
     '2022-04-13T05:00:00',
     '2022-04-13T06:00:00',
     '2022-04-13T06:59:59',
     '2022-04-13T08:00:00',
     '2022-04-13T09:00:00',
     '2022-04-13T09:59:59',
     '2022-04-13T11:00:00',
     '2022-04-13T12:00:00',
     '2022-04-13T12:59:59',
     '2022-04-13T14:00:00',
     '2022-04-13T15:00:00',
     '2022-04-13T15:59:59',
     '2022-04-13T17:00:00',
     '2022-04-13T18:00:00',
     '2022-04-13T18:59:59',
     '2022-04-13T20:00:00',
     '2022-04-13T21:00:00',
     '2022-04-13T21:59:59',
     '2022-04-13T23:00:00',
     '2022-04-14T00:00:00',
     '2022-04-14T00:59:59',
     '2022-04-14T02:00:00',
     '2022-04-14T03:00:00',
     '2022-04-14T03:59:59',
     '2022-04-14T05:00:00',
     '2022-04-14T06:00:00',
     '2022-04-14T06:59:59',
     '2022-04-14T08:00:00',
     '2022-04-14T09:00:00',
     '2022-04-14T09:59:59',
     '2022-04-14T11:00:00',
     '2022-04-14T12:00:00']},
   'forecast_reference_time': {'values': ['2022-04-11T12:00:00']}},
  'referencing': []},
 'parameters': {'hs': {'type': 'Parameter',
   'observedProperty': {'label': {'en': 'significant height of wind and swell waves'}},
   'description': {'en': 'significant height of wind and swell waves'},
   'unit': {'label': {'en': 'm'}}}},
 'ranges': {'hs': {'type': 'NdArray',
   'dataType': 'float',
   'axisNames': ['forecast_reference_time', 't'],
   'shape': [1, 73],
   'values': [0.33467215299606323,
    0.3588910698890686,
    0.3660368025302887,
    0.3152061402797699,
    0.2875429093837738,
    0.33364781737327576,
    0.42414912581443787,
    0.5218766927719116,
    0.599566638469696,
    0.6628382802009583,
    0.6959347724914551,
    0.7017455697059631,
    0.6900897026062012,
    0.6990023255348206,
    0.7459676861763,
    0.8135576248168945,
    0.8708090782165527,
    0.9190717339515686,
    0.9822579026222229,
    1.0730650424957275,
    1.1682802438735962,
    1.2368590831756592,
    1.2590762376785278,
    1.2461904287338257,
    1.2177737951278687,
    1.190627098083496,
    1.1743522882461548,
    1.1686142683029175,
    1.168257474899292,
    1.1705492734909058,
    1.1713541746139526,
    1.1505155563354492,
    1.1002039909362793,
    1.029807448387146,
    0.9527088403701782,
    0.8763468265533447,
    0.8059961199760437,
    0.7473487257957458,
    0.6959123611450195,
    0.6488614678382874,
    0.6027891635894775,
    0.5554247498512268,
    0.5091127157211304,
    0.4687694013118744,
    0.4349559545516968,
    0.40602195262908936,
    0.3779057264328003,
    0.3484857380390167,
    0.3213227689266205,
    0.30005601048469543,
    0.2922517955303192,
    0.3058054745197296,
    0.34318259358406067,
    0.39665448665618896,
    0.4514908790588379,
    0.4962618947029114,
    0.5274868011474609,
    0.5485127568244934,
    0.5546026825904846,
    0.5439878106117249,
    0.5306615829467773,
    0.521487832069397,
    0.5167329907417297,
    0.513405442237854,
    0.5168517827987671,
    0.531062662601471,
    0.5381449460983276,
    0.5489262938499451,
    0.570189356803894,
    0.6079721450805664,
    0.6753485798835754,
    0.7782320976257324,
    0.9024170637130737]}}}

datetime#

The next query param of interest to most users will be datetime. This will take either a single datetime and a range as ISO formatted string. To use a range, put a slash between the two times.

The trouble with timezones

The date format needs to match if the dataset is timezone aware, or not.

So we can add &datetime=2022-04-11T12:00:00/2022-04-11T23:00:00 to our previous query to restrict down the response further.

r = requests.get(
    "http://0.0.0.0:9005/datasets/ww3/edr/position"
    "?coords=POINT(-69.35 43.72)"
    "&parameter-name=sea_surface_wave_significant_height"
    "&datetime=2022-04-11T12:00:00/2022-04-11T23:00:00"
)
r.json()
{'type': 'Coverage',
 'domain': {'type': 'Domain',
  'domainType': 'Grid',
  'axes': {'t': {'values': ['2022-04-11T12:00:00',
     '2022-04-11T12:59:59',
     '2022-04-11T14:00:00',
     '2022-04-11T15:00:00',
     '2022-04-11T15:59:59',
     '2022-04-11T17:00:00',
     '2022-04-11T18:00:00',
     '2022-04-11T18:59:59',
     '2022-04-11T20:00:00',
     '2022-04-11T21:00:00',
     '2022-04-11T21:59:59',
     '2022-04-11T23:00:00']},
   'forecast_reference_time': {'values': ['2022-04-11T12:00:00']}},
  'referencing': []},
 'parameters': {'hs': {'type': 'Parameter',
   'observedProperty': {'label': {'en': 'significant height of wind and swell waves'}},
   'description': {'en': 'significant height of wind and swell waves'},
   'unit': {'label': {'en': 'm'}}}},
 'ranges': {'hs': {'type': 'NdArray',
   'dataType': 'float',
   'axisNames': ['forecast_reference_time', 't'],
   'shape': [1, 12],
   'values': [0.33467215299606323,
    0.3588910698890686,
    0.3660368025302887,
    0.3152061402797699,
    0.2875429093837738,
    0.33364781737327576,
    0.42414912581443787,
    0.5218766927719116,
    0.599566638469696,
    0.6628382802009583,
    0.6959347724914551,
    0.7017455697059631]}}}

f for format#

While CoverageJSON is useful for browser based access, other formats can be useful in other contexts. For that the f query parameter can be passed.

Currently csv for CSV files, and nc for NetCDF files have been added.

Extra coordinates#

If there are extra coordinates they can also be included as query parameters. Similar to the datetime query param, / is supported for a range to slice on in place of selecting.

For this dataset, if we used &time=2022-04-11T12:00:00/2022-04-11T23:00:00 we would have gotten the same result as the last query.

full_url = "http://0.0.0.0:9005/datasets/ww3/edr/position?coords=POINT(-69.35 43.72)&parameter-name=sea_surface_wave_significant_height,dir,t02&datetime=2022-04-11T12:00:00/2022-04-11T23:00:00&f=csv"

API Reference#

GET /datasets/{dataset_id}/edr/position#

Position query

Return position data based on WKT Point(lon lat) coordinate.

Extra selecting/slicing parameters can be provided as additional query strings.

Parameters
  • dataset_id (string) –

Query Parameters
  • coords (string) – Well Known Text coordinates (Required)

  • z (string) – Height or depth of query

  • datetime (string) – Query by a single ISO time or a range of ISO times. To query by a range, split the times with a slash

  • parameter-name (string) – xarray variables to query

  • crs (string) – CRS is not yet implemented

  • f (string) – Data is returned as a CoverageJSON by default, but NetCDF is supported with f=nc, or CSV with csv

Status Codes