diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8d64d..7b8549e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,4 +17,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -[Unreleased]: +[Unreleased]: diff --git a/README.md b/README.md index 17d3c2d..8787b70 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,18 @@ Example could be potentially incomplete code snippets that might be shown with c This extension is the successor of the [Example Links Extension](https://github.com/stac-extensions/example-links). +> [!NOTE] +> STAC is not best suited for describing applications through a STAC Item. +> This extension makes more sense to add additional context to geospatial data +> or can be used to describe applications in OGC API - Records. + - Examples: - - [Item example](examples/item.json): Shows the basic usage of the extension in a STAC Item + - [Catalog](examples/stac/catalog.json): Links to all examples below + - [Jupyter Notebook](examples/stac/jupyter-notebook.json) + - [Argo Workflow](examples/stac/argo-workflow.json) + - [openEO UDP](examples/stac/openeo-udp.json) + - [CWL / OGC Application Package](examples/stac/cwl-application-package.json) + - [Examples for usage in OGC API - Records](examples/ogcapi-records/) - [JSON Schema](json-schema/schema.json) - [Changelog](./CHANGELOG.md) @@ -53,6 +63,8 @@ Some common examples include: - `HTML` - `RMarkdown` +Please submit any new container via GitHub issues so that we can make a list of names everyone can reuse. + ### application:entrypoint Names the specific function, method or command to invoke in the referenced code. @@ -64,8 +76,8 @@ If not provided, the referenced code is expected to have a single, unambiguous e ### application:languages This fields lists all the languages the application is using, which can be programming or markup languages depending on the usecase. -Should be any of the [languages listed for Linguist](https://github.com/github-linguist/linguist/blob/master/lib/linguist/languages.yml), -e.g. `Python` or `R`. +Should be any of the [languages listed for Linguist](https://github.com/github-linguist/linguist/blob/master/lib/linguist/languages.yml) +if one exists (e.g. `Python` or `R`). Otherwise, custom values can be used (e.g. `openEO`). This field MUST NOT contain the container language (see above). @@ -74,11 +86,19 @@ See the [relation types](#relation-types) for when a reference is rendered inlin Highlighting SHOULD only be applied when exactly one language is listed and no `application:container` is set. +## Container and Language Specifics + +### Jupyter Notebooks + +Additional information about Jupyter Notebooks can also be embedded into the +Jupyter Notebook metadata section directly, see also Annex C of the +[CEOS Jupyter Notebook Best Practices](https://ceos.org/document_management/Working_Groups/WGISS/Documents/WGISS%20Best%20Practices/CEOS_JupterNotebooks_Best%20Practice_v1.1.pdf). + ## Usage Examples Examples can be provided directly as source code files or as a document with embedded code (e.g. web page, PDF document, Jupyter Notebook). -### Examples: Source Code Files +### Source Code Files The Link Object for a Python application that is rather large and is expected to be executed directly: @@ -109,7 +129,7 @@ highlighted code block: } ``` -### Examples: Code in a Container +### Code in a Container The Link Object for a PDF document with C code: @@ -178,25 +198,40 @@ The following types should be used as applicable `rel` types in the | describedby | A reference to prose documentation (e.g. an HTML page or PDF) that describes the application (or data). Use this for content that "renders itself", i.e. should not be loaded and rendered as code example. | | application | A reference to an application. | | application-platform | A reference to a platform that can execute applications, can also list an application that has executed the application (see also [`processing:facility`](https://github.com/stac-extensions/processing)). | +| application-input | A reference to actual or example inputs for the application, e.g. a parameters file. | +| application-execute | A reference to an endpoint or URL that triggers execution of the application, e.g. an [OGC API - Processes](https://ogcapi.ogc.org/processes/) endpoint or a web-based user interface. To reference the execution that *produced* a dataset (provenance), use `processing-execution` from the [Processing extension](https://github.com/stac-extensions/processing) instead. | | vcs | A reference to a version control system, e.g. the GitHub repository of the catalog or application. | -| manifest | A reference to a document describing the application in more detail, e.g. `package.json` (JavaScript), `pyproject.toml` (Python), or a CodeMeta file. | +| manifest | A reference to a document describing the application (may include its environment and dependencies) in more detail, e.g. `package.json` (JavaScript), `pyproject.toml` (Python), `environment.yml` (Conda), or a CodeMeta file. | + +### application + +As an alternative to linking to the application code, the processing extension +allows to embed the application code directly into the STAC entity via `processing:expression`. +This is commonly done for openEO processing results, for example. +It is important to note that this alternative is meant to be used only for describing how data was processed, +not for how it could be processed in the future. ## Media Types The following media types could be used as applicable `type` in the Link and Asset Objects: -| Media Type | Description | -| -------------------------------- | ----------- | -| application/vnd.codemeta.ld+json | Refers to a [CodeMeta](https://codemeta.github.io/) file/response. | +| Media Type | Description | +| ----------------------------------------- | ----------- | +| application/x-ipynb+json | A [Jupyter Notebook](https://nbformat.readthedocs.io/). Use with `"application:container": "Jupyter Notebook"`. | +| application/vnd.openeo+json;type=process | An [openEO](https://openeo.org) user-defined process (UDP). Use with `"application:languages": ["openEO"]`. | +| application/cwl, application/cwl+yaml, application/cwl+json | A [Common Workflow Language](https://www.commonwl.org) document (e.g. an [OGC Application Package](https://docs.ogc.org/bp/20-089r1.html)), either encoding, YAML or JSON. Use with `"application:container": "Common Workflow Language"`. | +| application/x-argo-workflow-yaml | An [Argo Workflows](https://argo-workflows.readthedocs.io/) manifest. Use with `"application:container": "Argo Workflow"`. | +| application/vnd.codemeta.ld+json | Refers to a [CodeMeta](https://codemeta.github.io/) file/response. | ## Roles The following types should be used as applicable `roles` in the Link or [Asset Object](https://github.com/radiantearth/stac-spec/blob/master/commons/assets.md#asset-object). -| Type | Description | -| ------- | ----------- | -| example | A reference to example data. | +| Role | Description | +| -------- | ----------- | +| example | Example data, see the `example` relation type for more details. | +| manifest | A manifest file, see the `manifest` relation type for more details. | ## Contributing diff --git a/examples/ogcapi-records/experiment.json b/examples/ogcapi-records/experiment.json new file mode 100644 index 0000000..ed58ad0 --- /dev/null +++ b/examples/ogcapi-records/experiment.json @@ -0,0 +1,116 @@ +{ + "id": "esa-cci-permafrost", + "title": "ESA CCI permafrost", + "type": "Feature", + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core" + ], + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json", + "https://stac-extensions.github.io/processing/v1.2.0/schema.json" + ], + "geometry": null, + "properties": { + "created": "2025-03-17T14:30:23.650003+00:00", + "updated": "2025-03-17T14:30:23.650003+00:00", + "type": "experiment", + "title": "ESA CCI permafrost", + "description": "cube generation workflow for esa-cci-permafrost", + "keywords": [ + "Earth Science" + ], + "contacts": [ + { + "name": "Tejas Morbagal Harish", + "organization": "Brockmann Consult GmbH", + "position": "", + "links": [ + { + "rel": "about", + "type": "text/html", + "href": "https://www.brockmann-consult.de/" + } + ], + "contactInstructions": "", + "roles": [ + "principal investigator" + ] + } + ], + "themes": [ + { + "concepts": [ + { + "id": "cryosphere" + } + ], + "scheme": "https://github.com/stac-extensions/osc#theme" + } + ], + "formats": [], + "license": "proprietary", + "osc:workflow": "esa-cci-permafrost" + }, + "linkTemplates": [], + "links": [ + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json", + "title": "Open Science Catalog" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json", + "title": "Experiments" + }, + { + "rel": "related", + "href": "../../workflows/esa-cci-permafrost/record.json", + "type": "application/json", + "title": "Workflow: ESA CCI permafrost" + }, + { + "rel": "child", + "href": "../../products/esa-cci-permafrost/collection.json", + "type": "application/json", + "title": "esa-cci-permafrost" + }, + { + "rel": "related", + "href": "../../projects/deep-earth-system-data-lab/collection.json", + "type": "application/json", + "title": "Project: DeepESDL" + }, + { + "rel": "application-input", + "href": "./input.yaml", + "type": "application/yaml", + "title": "Input parameters" + }, + { + "rel": "manifest", + "href": "./environment.yaml", + "type": "application/yaml", + "title": "Execution environment" + }, + { + "rel": "processing-execution", + "href": "https://deep.earthsystemdatalab.net/hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2Fdeepesdl%2Fcube-gen&urlpath=lab%2Ftree%2Fcube-gen%2FPermafrost%2FCreate-CCI-Permafrost-cube-EarthCODE.ipynb&branch=main", + "type": "text/html", + "title": "Execution that produced this experiment on the DeepESDL platform" + }, + { + "rel": "self", + "href": "https://esa-earthcode.github.io/open-science-catalog-metadata/experiments/esa-cci-permafrost/record.json", + "type": "application/json" + }, + { + "rel": "related", + "href": "../../themes/cryosphere/catalog.json", + "type": "application/json", + "title": "Theme: Cryosphere" + } + ] +} diff --git a/examples/item.json b/examples/ogcapi-records/workflow.json similarity index 67% rename from examples/item.json rename to examples/ogcapi-records/workflow.json index 7e72b29..b194809 100644 --- a/examples/item.json +++ b/examples/ogcapi-records/workflow.json @@ -1,21 +1,52 @@ { - "stac_version": "1.1.0", - "stac_extensions": [ - "https://stac-extensions.github.io/application/v0.1.0/schema.json" - ], "id": "esa-cci-permafrost", "type": "Feature", + "conformsTo": [ + "http://www.opengis.net/spec/ogcapi-records-1/1.0/req/record-core" + ], + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json", + "https://stac-extensions.github.io/vcs/v0.1.0/schema.json" + ], "geometry": null, "properties": { - "datetime": "2025-03-17T14:30:23Z", + "created": "2025-03-17T14:30:23.650003+00:00", + "updated": "2025-04-25T14:00:00Z", "type": "workflow", "title": "ESA CCI permafrost", "description": "cube generation workflow for esa-cci-permafrost", "application:container": "Jupyter Notebook", - "application:languages": [ - "Python" - ] + "application:languages": ["Python"], + "keywords": ["Earth Science"], + "contacts": [ + { + "name": "Tejas Morbagal Harish", + "organization": "Brockmann Consult GmbH", + "links": [ + { + "rel": "about", + "type": "text/html", + "href": "https://www.brockmann-consult.de/" + } + ], + "roles": ["principal investigator"] + } + ], + "themes": [ + { + "concepts": [ + { + "id": "cryosphere" + } + ], + "scheme": "https://github.com/stac-extensions/osc#theme" + } + ], + "formats": [], + "license": "proprietary", + "osc:project": "deep-earth-system-data-lab" }, + "linkTemplates": [], "links": [ { "rel": "root", @@ -66,24 +97,7 @@ "file:local_path": "Permafrost/Create-CCI-Permafrost-cube-EarthCODE.ipynb", "type": "application/x-ipynb+json", "application:container": "Jupyter Notebook", - "application:languages": [ - "Python" - ], - "jupyter:kernel": { - "name": "deepesdl-xcube-1.8.3", - "pythonVersion": "3.11", - "envFile": "https://github.com/deepesdl/cube-gen/blob/main/Permafrost/environment.yml" - } - }, - { - "rel": "example", - "title": "Cube generation script", - "href": "https://github.com/deepesdl/cube-gen/blob/main/Permafrost/cube.py", - "type": "text/x-python", - "application:entrypoint": "generate_cube", - "application:languages": [ - "Python" - ] + "application:languages": ["Python"] }, { "rel": "application-platform", @@ -92,10 +106,10 @@ "type": "text/html" }, { - "rel": "related", + "rel": "application-execute", "href": "https://deep.earthsystemdatalab.net/hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2Fdeepesdl%2Fcube-gen&urlpath=lab%2Ftree%2Fcube-gen%2FPermafrost%2FCreate-CCI-Permafrost-cube-EarthCODE.ipynb&branch=main", - "title": "Open notebook on the DeepESDL platform" + "title": "Open notebook on the DeepESDL platform", + "type": "text/html" } - ], - "assets": {} -} \ No newline at end of file + ] +} diff --git a/examples/stac/argo-workflow.json b/examples/stac/argo-workflow.json new file mode 100644 index 0000000..11e1bc9 --- /dev/null +++ b/examples/stac/argo-workflow.json @@ -0,0 +1,69 @@ +{ + "stac_version": "1.1.0", + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json", + "https://stac-extensions.github.io/vcs/v0.1.0/schema.json" + ], + "id": "polaris", + "type": "Feature", + "geometry": null, + "properties": { + "datetime": "2025-02-19T23:00:00Z", + "title": "POLARIS", + "description": "Polar Operational Limit Assessment Risk Index System (POLARIS) algorithm.", + "license": "CC-BY-SA-4.0", + "application:container": "Argo Workflow", + "application:languages": [ + "Python" + ] + }, + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "parent", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "self", + "href": "https://stac-extensions.github.io/application/v0.1.0/examples/stac/argo-workflow.json", + "type": "application/json" + }, + { + "rel": "vcs", + "href": "https://github.com/gtif-cerulean/polaris.git", + "title": "Git source repository", + "vcs:type": "git", + "vcs:branch": "main" + }, + { + "rel": "application", + "href": "https://github.com/gtif-cerulean/polaris/blob/main/workflow.yml", + "title": "POLARIS workflow", + "type": "application/x-argo-workflow-yaml", + "application:container": "Argo Workflow", + "application:languages": [ + "Python" + ] + }, + { + "rel": "application-platform", + "href": "https://workspace.cif.hub-otc.eox.at/", + "title": "EOxHub Workspaces", + "type": "text/html" + }, + { + "rel": "application-execute", + "href": "https://harshness-map.gtif.eox.at/processes/execute-polaris", + "title": "Trigger the workflow via pygeoapi", + "type": "text/html" + } + ], + "assets": {} +} diff --git a/examples/stac/catalog.json b/examples/stac/catalog.json new file mode 100644 index 0000000..2ce8368 --- /dev/null +++ b/examples/stac/catalog.json @@ -0,0 +1,43 @@ +{ + "stac_version": "1.1.0", + "type": "Catalog", + "id": "application-examples", + "description": "Examples for the Application extension, one per application type.", + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "self", + "href": "https://stac-extensions.github.io/application/v0.1.0/examples/stac/catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "./jupyter-notebook.json", + "type": "application/json", + "title": "Jupyter Notebook" + }, + { + "rel": "child", + "href": "./argo-workflow.json", + "type": "application/json", + "title": "Argo Workflow" + }, + { + "rel": "child", + "href": "./openeo-udp.json", + "type": "application/json", + "title": "openEO UDP" + }, + { + "rel": "child", + "href": "./cwl-application-package.json", + "type": "application/json", + "title": "CWL / OGC Application Package" + } + ] +} diff --git a/examples/stac/cwl-application-package.json b/examples/stac/cwl-application-package.json new file mode 100644 index 0000000..5941587 --- /dev/null +++ b/examples/stac/cwl-application-package.json @@ -0,0 +1,57 @@ +{ + "stac_version": "1.1.0", + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json", + "https://stac-extensions.github.io/vcs/v0.1.0/schema.json" + ], + "id": "fairsendd", + "type": "Feature", + "geometry": null, + "properties": { + "datetime": "2025-01-01T00:00:00Z", + "title": "FAIRSenDD: FAIR workflow for Sentinel-1 based Deforestation Detection", + "description": "Detects forest change in Sentinel-1 time series using Recurrence Quantification Analysis, published as an OGC Application Package.", + "license": "MIT", + "application:container": "Common Workflow Language", + "application:languages": [ + "Julia" + ] + }, + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "parent", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "self", + "href": "https://stac-extensions.github.io/application/v0.1.0/examples/stac/cwl-application-package.json", + "type": "application/json" + }, + { + "rel": "vcs", + "href": "https://github.com/EarthyScience/FAIRSenDD", + "title": "Git source repository", + "vcs:type": "git", + "vcs:branch": "main" + }, + { + "rel": "application", + "href": "https://raw.githubusercontent.com/EarthyScience/FAIRSenDD/refs/heads/main/ogc-app-cwl/fairsendd.cwl", + "title": "OGC Application Package", + "type": "application/cwl+yaml", + "application:container": "Common Workflow Language", + "application:languages": [ + "Julia" + ] + } + ], + "assets": {} +} diff --git a/examples/stac/jupyter-notebook.json b/examples/stac/jupyter-notebook.json new file mode 100644 index 0000000..032a798 --- /dev/null +++ b/examples/stac/jupyter-notebook.json @@ -0,0 +1,75 @@ +{ + "stac_version": "1.1.0", + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json", + "https://stac-extensions.github.io/vcs/v0.1.0/schema.json" + ], + "id": "esa-cci-permafrost", + "type": "Feature", + "geometry": null, + "properties": { + "datetime": "2025-03-17T14:30:23Z", + "title": "ESA CCI permafrost", + "description": "Cube generation workflow for esa-cci-permafrost.", + "application:container": "Jupyter Notebook", + "application:languages": [ + "Python" + ] + }, + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "parent", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "self", + "href": "https://stac-extensions.github.io/application/v0.1.0/examples/stac/jupyter-notebook.json", + "type": "application/json" + }, + { + "rel": "vcs", + "href": "https://github.com/deepesdl/cube-gen.git", + "title": "Git source repository", + "vcs:type": "git", + "vcs:branch": "main" + }, + { + "rel": "application", + "href": "https://github.com/deepesdl/cube-gen/blob/main/Permafrost/Create-CCI-Permafrost-cube-EarthCODE.ipynb", + "title": "Create CCI Permafrost cube", + "type": "application/x-ipynb+json", + "file:local_path": "Permafrost/Create-CCI-Permafrost-cube-EarthCODE.ipynb", + "application:container": "Jupyter Notebook", + "application:languages": [ + "Python" + ] + }, + { + "rel": "manifest", + "href": "https://github.com/deepesdl/cube-gen/blob/main/Permafrost/environment.yml", + "title": "conda environment", + "type": "application/yaml" + }, + { + "rel": "application-platform", + "href": "https://deep.earthsystemdatalab.net/", + "title": "DeepESDL platform", + "type": "text/html" + }, + { + "rel": "application-execute", + "href": "https://deep.earthsystemdatalab.net/hub/user-redirect/git-pull?repo=https%3A%2F%2Fgithub.com%2Fdeepesdl%2Fcube-gen&urlpath=lab%2Ftree%2Fcube-gen%2FPermafrost%2FCreate-CCI-Permafrost-cube-EarthCODE.ipynb&branch=main", + "title": "Open the notebook on the DeepESDL platform", + "type": "text/html" + } + ], + "assets": {} +} diff --git a/examples/stac/openeo-udp.json b/examples/stac/openeo-udp.json new file mode 100644 index 0000000..0471cd9 --- /dev/null +++ b/examples/stac/openeo-udp.json @@ -0,0 +1,58 @@ +{ + "stac_version": "1.1.0", + "stac_extensions": [ + "https://stac-extensions.github.io/application/v0.1.0/schema.json" + ], + "id": "esa-world-cereal-extent", + "type": "Feature", + "geometry": null, + "properties": { + "datetime": "2026-04-01T07:16:38Z", + "title": "ESA WorldCereal - Crop Type Extent", + "description": "Detects crop land at 10m resolution, trained for global use. Based on Sentinel-1 and 2 data, applying a Presto + CatBoost model to map the extent of crops.", + "application:languages": [ + "openEO" + ] + }, + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "parent", + "href": "./catalog.json", + "type": "application/json", + "title": "Application examples" + }, + { + "rel": "self", + "href": "https://stac-extensions.github.io/application/v0.1.0/examples/stac/openeo-udp.json", + "type": "application/json" + }, + { + "rel": "application", + "href": "https://s3.waw4-1.cloudferro.com/workflows/prod/esa-world-cereal-extent-workflow/worldcereal_crop_extent.json", + "title": "openEO user-defined process", + "type": "application/vnd.openeo+json;type=process", + "application:languages": [ + "openEO" + ] + }, + { + "rel": "application-platform", + "href": "https://dataspace.copernicus.eu/", + "title": "Copernicus Data Space Ecosystem", + "type": "text/html" + }, + { + "rel": "application-execute", + "href": "https://editor.openeo.org/?wizard=UDP&wizard~process=worldcereal_crop_extent&wizard~processUrl=https://s3.waw4-1.cloudferro.com/workflows/prod/esa-world-cereal-extent-workflow/worldcereal_crop_extent.json&server=https://openeofed.dataspace.copernicus.eu/openeo", + "title": "Run in the openEO Web Editor", + "type": "text/html" + } + ], + "assets": {} +} diff --git a/package.json b/package.json index e249c11..4ff6e85 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "scripts": { "test": "npm run check-markdown && npm run check-examples", "check-markdown": "remark . -f -r .github/remark.yaml", - "check-examples": "stac-node-validator . --lint --verbose --schemaMap https://stac-extensions.github.io/application/v0.1.0/schema.json=./json-schema/schema.json", - "format-examples": "stac-node-validator . --format --schemaMap https://stac-extensions.github.io/application/v0.1.0/schema.json=./json-schema/schema.json" + "check-examples": "stac-node-validator examples/stac --lint --verbose --schemaMap https://stac-extensions.github.io/application/v0.1.0/schema.json=./json-schema/schema.json", + "format-examples": "stac-node-validator examples/stac --format --schemaMap https://stac-extensions.github.io/application/v0.1.0/schema.json=./json-schema/schema.json" }, "dependencies": { "remark-cli": "^12.0.0", @@ -16,6 +16,6 @@ "remark-preset-lint-markdown-style-guide": "^6.0.0", "remark-preset-lint-recommended": "^7.0.0", "remark-validate-links": "^13.0.0", - "stac-node-validator": "^1.3.0" + "stac-node-validator": "^2.0.0" } }