diff --git a/api/README.md b/api/README.md index b318be44..383435a5 100644 --- a/api/README.md +++ b/api/README.md @@ -12,6 +12,36 @@ Environment variables that can be used to configure the container or the environ | GUNICORN_CMD_ARGS | Command-line arguments for configuring Gunicorn, a Python WSGI HTTP Server. | ☐ | | CORS_ORIGINS | Indicates whether the response can be shared with requesting code from the given origins (passed as a comma separated string) | ☐ | | CORS_HEADERS | Indicates what headers should be supported with cross-origin requests (passed as a comma separated string) | ☐ | +| JINJA2_TEMPLATES | Path to a folder with jinja2 templates to override the default templates used by the API. See template section for details | ☐ | +| OPENAPI_METADATA_PATH | Path to an alternative OpenAPI metadata json file. It need to have the same fields as the openapi/openapi_metadata.py file. | ☐ | + +## OpenAPI and EDR landing page metadata + +To load your own metadata file, mount your new openapi metadata json file, with the same structure and key as the default one, found in openapi_default_files, and point the environment variable `OPENAPI_METADATA_PATH` to the new file. If you mount your folder to the same as the default one, make sure to not overwrite files you have not replaced. + +This Metdata is used both for the OpenAPI specification and the EDR landing page. + +The available fields are: title, version, summary, description, terms_of_service, contact, license_info, tags, external_docs. + +## JINJA2_TEMPLATES + +The jinja2 folder must container the following files: + +- dataset_metadata_template.j2: this is the metadata template for the observation collection. + +### dataset_metadata_template.j2 + +The current jinja2 filters will be replaced. It's important to use the json j2 filter when inserting these strings. + +- spatial_extent +- temporal_extent +- url_base +- url_conformance +- url_docs + +All url fields are dynamically generated based on the request url base. + +To load a custom template, mount a folder with your new template in to the container and set the `JINJA2_TEMPLATES` environment variable to point your new folder. ## Prerequisites of running locally diff --git a/api/openapi/openapi_metadata.py b/api/openapi/openapi_metadata.py index 52a1fff9..1cd329e0 100644 --- a/api/openapi/openapi_metadata.py +++ b/api/openapi/openapi_metadata.py @@ -1,16 +1,21 @@ -openapi_metadata = { - "title": "EDR Observations API Europe EUMETNET", - "description": ( - "OGC EDR API data service for European meteorological observations from EUMETNET," - " co-funded by the European Union." - ), - "contact": { - "name": "EUMETNET", - "url": "https://www.eumetnet.eu/about-us/", - "email": "eucos@metoffice.gov.uk", - }, - "license_info": { - "name": "CC-BY-4.0", - "url": "https://creativecommons.org/licenses/by/4.0/", - }, -} +import os +import json + +with open( + os.getenv("OPENAPI_METADATA_PATH", "/app/openapi_default_files/openapi_metadata.json"), + "r", +) as file: + openapi_metadata = json.load(file) + valid_keys = [ + "title", + "version", + "summary", + "description", + "terms_of_service", + "contact", + "license_info", + "openapi_tags", + ] + unwanted = set(openapi_metadata) - set(valid_keys) + for unwanted_key in unwanted: + del openapi_metadata[unwanted_key] diff --git a/api/openapi_default_files/openapi_metadata.json b/api/openapi_default_files/openapi_metadata.json new file mode 100644 index 00000000..a1131887 --- /dev/null +++ b/api/openapi_default_files/openapi_metadata.json @@ -0,0 +1,13 @@ +{ + "title": "EDR Observations API Europe EUMETNET", + "description": "OGC EDR API data service for European meteorological observations from EUMETNET, co-funded by the European Union.", + "contact": { + "name": "EUMETNET", + "url": "https://www.eumetnet.eu/about-us/", + "email": "eucos@metoffice.gov.uk" + }, + "license_info": { + "name": "CC-BY-4.0", + "url": "https://creativecommons.org/licenses/by/4.0/" + } +} diff --git a/api/routers/feature.py b/api/routers/feature.py index 4a941284..e0afc149 100644 --- a/api/routers/feature.py +++ b/api/routers/feature.py @@ -1,4 +1,5 @@ import json +import os from typing import Annotated import datastore_pb2 as dstore @@ -23,7 +24,7 @@ router = APIRouter(prefix="/collections/observations") -env = Environment(loader=FileSystemLoader("templates"), autoescape=select_autoescape()) +env = Environment(loader=FileSystemLoader(os.getenv("JINJA2_TEMPLATES", "templates")), autoescape=select_autoescape()) @router.get( @@ -174,10 +175,7 @@ async def get_dataset_metadata(request: Request): ] ], "temporal_extents": [ - [ - f"{extent.temporal_extent.start.ToDatetime().strftime('%Y-%m-%dT%H:%M:%SZ')}", - f"{extent.temporal_extent.end.ToDatetime().strftime('%Y-%m-%dT%H:%M:%SZ')}", - ], + [f"{extent.temporal_extent.start.ToDatetime().strftime('%Y-%m-%dT%H:%M:%SZ')}", ".."], ], "url_base": base_url, "url_conformance": base_url + "conformance", diff --git a/api/templates/dataset_metadata_template.j2 b/api/templates/dataset_metadata_template.j2 index aab0e420..48455276 100644 --- a/api/templates/dataset_metadata_template.j2 +++ b/api/templates/dataset_metadata_template.j2 @@ -1,9 +1,9 @@ { - "id": "urn:wmo:md:eu-eumetnet-observations:swob-realtime", + "id": "urn:wmo:md:eu-eumetnet-surface-observations:land-station-observations", "conformsTo": [ - "http://wis.wmo.int/spec/wcmp/2/conf/core" - ], - "type": "Feature", + "http://wis.wmo.int/spec/wcmp/2/conf/core" + ], + "type": "Feature", "geometry": { "type": "Polygon", "coordinates": {{ spatial_extents }} @@ -12,105 +12,136 @@ "interval": {{ temporal_extents|tojson }}, "resolution": "PT10M" }, - "properties": { - "title": "Land surface weather observations", - "description": "Land surface observations measured at automatic and manual stations of EUMETNET Members (last 24 hours)", - "themes": [ - { - "concepts": [ - { - "id": "weather" - } - ], - "scheme": "https://codes.wmo.int/wis/topic-hierarchy/earth-system-discipline" - }, - { - "concepts": [ - { - "id": "surface-based-observations" - } - ], - "scheme": "https://codes.wmo.int/wis/topic-hierarchy/earth-system-discipline/_weather" - } +"properties": { + "title": "Land surface weather observations", + "description":"Land surface observations measured at automatic and manual weather stations of EUMETNET Members and their trusted partners (last 24 hours only)", + "contacts": [ + { + "name": "Met Norway", + "organization": "National Meteorological service of Norway, Met Norway", + "phones": [ + { + "value": "+4722963000" + } ], - "language": "en", - "type": "dataset", - "created": "2023-01-01T00:00:00Z", - "updated": "2024-09-19T00:00:00Z", - "contacts": [ - { - "organization": "EUMETNET", - "addresses": [ - { - "deliveryPoint": [ - "Avenue Circulaire 3" - ], - "city": "Bruxelles", - "postalCode": "1180", - "country": "Belgique" - } - ], - "links": [ - { - "href": "https://www.eumetnet.eu/about-us/", - "rel": "about", - "type": "text/html" - } - ], - "roles": [ - "host" - ] - } + "emails": [ + { + "value": "post@met.no" + } ], - "keywords": [ - "surface weather", - "observations", - "meteorology" + "addresses": [ + { + "deliveryPoint": [ + "https://www.met.no/en/contact-us" + ], + "name": "Met Norway", + "city": "Oslo", + "postalCode": "0313", + "country": "Norway" + } ], - "wmo:dataPolicy": "core" - }, - "links": [ - { - "href": "E-SOH dataset mqtt stream", - "rel": "items", - "title": "E-SOH dataset data notifications", - "type": "application/json" - }, - { - "href": "E-SOH time series mqtt stream", - "rel": "items", - "title": "E-SOH time series data notifications", - "type": "application/json" - }, - { - "href": {{ url_base|tojson }}, - "rel": "data", - "title": "E-SOH EDR API landing page", - "type": "application/json" - }, - { - "href": {{ url_docs|tojson }}, - "rel": "related", - "title": "E-SOH API documentation", - "type": "application/json" - }, - { - "href": {{ url_conformance|tojson }}, - "rel": "conformance", - "title": "E-SOH Conformance Declaration", - "type": "application/json" - }, - { - "href": "https://www.eumetnet.eu/wp-content/uploads/2018/03/List-of-current-Members-as-pdf.pdf", + "links": [ + { "rel": "about", - "title": "EUMETNET Members", - "type": "text/html" + "type": "text/html", + "href": "https://www.eumetnet.eu/about-us" + } + ], + "roles": ["host"] + } + ], + "keywords": [ + "weather", + "surface-based observations", + "observations", + "meteorology", + "surface weather", + "Norway", + "Finland", + "The Netherlands" + ], + "themes": [ + { "concepts": [ + { + "id":"weather", + "title": "Weather", + "url": "https://codes.wmo.int/wis/topic-hierarchy/earth-system-discipline/weather" + } + ], + "scheme":"https://codes.wmo.int/wis/topic-hierarchy/earth-system-discipline" + }, + { "concepts": [ + { + "id":"surface-based-observations" + } + ], + "scheme":"https://codes.wmo.int/wis/topic-hierarchy/earth-system-discipline/weather/surface-based-observations" }, - { - "href": "https://creativecommons.org/licenses/by/4.0/", - "rel": "license", - "title": "Creative Commons BY 4.0 licence", - "type": "text/html" - } - ] + { + "concepts": [ + { + "id": "air_temperature", + "title": "Air temperature", + "url": "http://vocab.nerc.ac.uk/standard_name/air_temperature/" + }, + { + "id": "wind_speed", + "title": "Wind Speed", + "url": "http://vocab.nerc.ac.uk/standard_name/wind_speed/" + }, + { + "id": "wind_to_direction", + "title": "Wind to diection", + "url": "http://vocab.nerc.ac.uk/standard_name/wind_to_direction/" + } + ], + "scheme": "https://vocab.nerc.ac.uk/standard_name" + } + ], + "language":"en", + "created": "2025-06-04T14:00:00Z", + "updated": "2025-06-04T14:00:00Z", + "rights": "Users are granted free and unrestricted access to this data, without charge and with no conditions on use. Users are requested to attribute the producer of this data. WMO Unified Data Policy (Resolution 1 (Cg-Ext 2021))", + "licence": "CC BY 4.0 Creative Commons license", + "type": "dataset", + "wmo:dataPolicy": "recommended" + }, + "links": [ + { + "href": {{ url_base|tojson }}, + "rel": "data", + "title": "E-SOH EDR API landing page", + "type": "application/json" + }, + { + "href": {{ url_docs|tojson }}, + "rel": "related", + "title": "E-SOH API documentation", + "type": "application/json" + }, + { + "href": {{ url_conformance|tojson }}, + "rel": "conformance", + "title": "E-SOH Conformance Declaration", + "type": "application/json" + }, + { + "rel": "related", + "href": "https://www.eumetnet.eu/observations/observations-data-sharing-2/", + "type": "text/html", + "title": "Documentation related to EUMETNET data sharing" + }, + { + "rel": "related", + "href": "https://www.eumetnet.eu/about-us-2/members-partners/", + "type": "text/html", + "title": "List of EUMETNET Members" + }, + { + "rel": "license", + "href": "https://creativecommons.org/licenses/by/4.0/", + "title": "Creative Commons BY 4.0 licence", + "type": "text/html" + } + ] }