diff --git a/.circleci/build-openapi.sh b/.circleci/build-openapi.sh index a8843011..55e555e6 100755 --- a/.circleci/build-openapi.sh +++ b/.circleci/build-openapi.sh @@ -10,11 +10,9 @@ for fin in $FNAMES; do fout=./build/$fin mkdir -p ${fout%/*} openapi bundle --ext yaml --output $fout $fin - cp build/index.html ${fout%/*}/ + cp build/redoc_index.html ${fout%/*}/index.html done -cp build/core/openapi.yaml build/openapi.yaml - # use swagger-combine #swagger-combine build/swagger-config.yaml --continueOnConflictingPaths -o build/openapi.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index a08e4299..f5b81651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,35 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [v1.0.0-beta4] - 2020-10-05 ### Added +- Support binding Sort, Fields, and Context Extensions to STAC Features items resource + endpoint (`/collections/{collection_id}/items`) +- In Collections, added `canonical` rel type, added `/` and `/api` to list of endpoints +- In Item Search, added endpoint table + ### Changed +- Filter Extension - query language is now referred to as "CQL2" rather than CQL +- Filter Extension now uses OAFeat Part 3 conformance class URIs +- Filter Extension - The following changes have been made to the Filter Extension conformance classes to align with changes to the OAFeat CQL draft. All classes + whose names have changed also have changed conformance URI strings. + - "Basic CQL" now includes the "not equal" operator (`<>`) + - "Basic CQL" has always supported datetime comparisons, but this is now explicitly mentioned + - "Enhanced Comparison Operators" has been renamed "Advanced Comparison Operators". This is the same as the OAFeat CQL definition, except + that it does not require the `upper` and `lower` functions. + - "Enhanced Spatial Operators" has been renamed to just "Spatial Operators" (not to be confused with Basic Spatial Operators) + - "Basic Temporal Operators" and "Enhanced Temporal Operators" have merged into "Temporal Operators" + - "Functions" has been renamed "Custom Functions" + - "Arithmetic" has been renamed "Arithmetic Expressions" + - "Arrays" has been renamed "Array Operators" + - "Queryable Second Operand" has been renamed "Property-Property Comparisons" +- The required Link Relations and endpoints for each conformance class now use the wording of 'shall' + instead of 'should'. While this technically changes the semantics, it was generally understood + previously the semantics were those of 'shall' (must). + ### Deprecated ### Removed diff --git a/README.md b/README.md index ccd78cd0..dd274503 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ to search STAC catalogs, where the features returned are STAC [Item](stac-spec/i that have common properties, links to their assets and geometries that represent the footprints of the geospatial assets. The specification for STAC API is provided as files that follow the [OpenAPI](http://openapis.org/) 3.0 specification, -rendered online into HTML at , in addition to human-readable documentation. +rendered online into HTML at , in addition to human-readable documentation. ## Stability Note diff --git a/build/index.html b/build/index.html index 11b22352..3615bf48 100644 --- a/build/index.html +++ b/build/index.html @@ -2,31 +2,22 @@ - STAC API - - - - - - - + STAC API + + + + - - +

STAC API

+

Conformance Classes

+ - \ No newline at end of file + diff --git a/build/redoc_index.html b/build/redoc_index.html new file mode 100644 index 00000000..9ba1d22a --- /dev/null +++ b/build/redoc_index.html @@ -0,0 +1,32 @@ + + + + + STAC API + + + + + + + + + + + + + + + diff --git a/build/swagger-config.yaml b/build/swagger-config.yaml index ad056d8e..86256693 100644 --- a/build/swagger-config.yaml +++ b/build/swagger-config.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: STAC API - Complete - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 apis: - url: 'build/core/openapi.yaml' paths: diff --git a/collections/README.md b/collections/README.md index aa091ea0..2fafff84 100644 --- a/collections/README.md +++ b/collections/README.md @@ -4,10 +4,9 @@ - [Link Relations](#link-relations) - [Endpoints](#endpoints) - [Example](#example) - - [Conformance](#conformance) -- **OpenAPI specification:** Missing -- **Conformance URI:** +- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.4/collections)) +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Dependencies**: [STAC API - Core](../core) @@ -23,120 +22,126 @@ aim to align with it. But it still seems to be in flux.* ## Link Relations -The following Link relations should exist in the Landing Page (root). +The following Link relations shall exist in the Landing Page (root). | **rel** | **href** | **From** | **Description** | | -------------- | -------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `root` | `/` | STAC Core | The root URI | | `self` | `/` | OAFeat | Self reference, same as root URI | -| `service-desc` | `/api` (recommended) | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API | -| `child` | various | STAC Core | The child STAC Catalogs & Collections. Provides curated paths to get to STAC Collection and Item objects | -| `data` | `/collections` | OAFeat | List of Collections | +| `service-desc` | `/api` | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API. The path for this endpoint is only recommended to be `/api`, but may be another path. | +| `data` | `/collections` | OAFeat | List of Collections | -Additionally, a `service-doc` endpoint is recommended. +A `service-doc` endpoint is recommended, but not required. -| **rel** | **href** | **From** | **Description** | +| **rel** | **href** | **From** | **Description** | | ------------- | ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `service-doc` | `/api.html` (recommended) | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service | +| `service-doc` | `/api.html` | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service. The path for this endpoint is only recommended to be `/api.html`, but may be another path. | -The following Link relations should exist in the `/collections` endpoint response. +Additionally, `child` relations may exist to individual catalogs and collections. + +| **rel** | **href** | **From** | **Description** | +| -------------- | -------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `child` | various | STAC Core | The child STAC Catalogs & Collections. Provides curated paths to get to STAC Collection and Item objects | + +`child` relations are useful for supporting browsing a STAC API as if it were a static catalog. + +The following Link relations shall exist in the `/collections` endpoint response. | **rel** | **href** | **From** | **Description** | | ------- | -------------- | --------- | --------------- | | `root` | `/` | STAC Core | The root URI | | `self` | `/collections` | OAFeat | Self reference | -The following Link relations should exist in the `/collections/{collectionId}` endpoint response. +The following Link relations shall exist in the Collection object returned from the `/collections/{collectionId}` endpoint. | **rel** | **href** | **From** | **Description** | | -------- | ----------------------------------- | --------- | ------------------------------------------ | | `root` | `/` | STAC Core | The root URI | | `parent` | `/` | OAFeat | Parent reference, usually the root Catalog | | `self` | `/collections/{collectionId}` | OAFeat | Self reference | -| `items` | `/collections/{collectionId}/items` | OAFeat | Items within Collection | + +Additionally, these relations may exist for the `/collections/{collectionId}` endpoint: + +| **rel** | **href** | **From** | **Description** | +| -------- | ----------------------------------- | --------- | ------------------------------------------ | +| `canonical` | various | STAC Core | Provides the preferred paths to get to STAC Collection and Item objects, if they differ from the URL that was used to retrieve the STAC object and thus duplicate other content. This can be useful in federated catalogs that present metadata that has a different location than the source metadata. | + +Usually, the `self` link in a Collection must link to the same URL that was used to request +it. However, implementations may choose to have the canonical location of the Collection be +elsewhere. If this is done, it is recommended to include a `rel` of `canonical` to that location. ## Endpoints -| Endpoint | Returns | Description | -| ----------------------------- | ---------- | -------------------------------------------------------------------- | -| `/collections` | JSON | Object with a list of Collections contained in the catalog and links | -| `/collections/{collectionId}` | Collection | Returns single Collection JSON | +| Endpoint | Returns | Description | +| -------- | ------- | ----------- | +| `/` | Catalog | Landing Page and root Catalog | +| `/api` | OAFeat OpenAPI | The OpenAPI service description. The path for this endpoint is only recommended to be `/api`, but may be another path. | +| `/collections` | JSON | Object with a list of Collections contained in the catalog and links | +| `/collections/{collectionId}` | Collection | Returns single Collection JSON | STAC API's implementing the Collections class must support HTTP GET operation at `/collections`, with the return JSON document consisting of an array of all STAC Collections and an array of Links. ## Example +Below is a minimal example, but captures the essence. Each collection object must be a valid STAC +[Collection](../stac-spec/collection-spec/README.md), and each must have a `self` link that communicates its canonical location. And then +the links section must include a `self` link, and it must also link to alternate representations (like html) of the collection. + ```json { - "collections": [ - { - "stac_version": "1.0.0", - "stac_extensions": [ ], - "id": "cool-data", - "title": "Cool Data from X Satellite", - "description": "A lot of awesome words describing the data", - "license": "CC-BY", - "extent": { - "spatial": { - "bbox": [[-135.17, 36.83, -51.24, 62.25]] - }, - "temporal": { - "interval": [["2009-01-01T00:00:00Z",null]] - } - }, - "links": [ - { - "rel": "root", - "type": "application/json", - "href": "https://myservice.com" - }, - { - "rel": "parent", - "type": "application/json", - "href": "https://myservice.com" - }, - { - "rel": "self", - "type": "application/json", - "href": "https://myservice.com/collections/cool-data" - }, - { - "rel": "items", - "type": "application/json", - "href": "https://myservice.com/collections/cool-data/items" - } - ], - } - ], - "links": [ - { - "rel": "root", - "type": "application/json", - "href": "https://myservice.com" - }, - { - "rel": "self", - "type": "application/json", - "href": "https://myservice.com/collections" - } - ] + "collections": [ + { + "stac_version": "1.0.0", + "stac_extensions": [ ], + "id": "cool-data", + "title": "Cool Data from X Satellite", + "description": "A lot of awesome words describing the data", + "type": "Collection", + "license": "CC-BY", + "extent": { + "spatial": { + "bbox": [[-135.17, 36.83, -51.24, 62.25]] + }, + "temporal": { + "interval": [["2009-01-01T00:00:00Z",null]] + } + }, + "links": [ + { + "rel": "root", + "type": "application/json", + "href": "https://myservice.com" + }, + { + "rel": "parent", + "type": "application/json", + "href": "https://myservice.com" + }, + { + "rel": "self", + "type": "application/json", + "href": "https://myservice.com/collections/cool-data" + }, + { + "rel": "items", + "type": "application/json", + "href": "https://myservice.com/collections/cool-data/items" + } + ], + } + ], + "links": [ + { + "rel": "root", + "type": "application/json", + "href": "https://myservice.com" + }, + { + "rel": "self", + "type": "application/json", + "href": "https://myservice.com/collections" + } + ] } ``` - -The above is a minimal example, but captures the essence. Each collection object must be a valid STAC -[Collection](../stac-spec/collection-spec/README.md), and each should have a `self` link that communicates its canonical location. And then -the links section must include a `self` link, and it should also link to alternate representations (like html) of the collection. - -Each collection must also be accessible from `/collections/{collectionId}`. Usually this will be the location provided by the `self` link, -but implementations may choose to list the canonical location elsewhere. But `/collections/{collectionId}` must always contain the response, -and if the canonical location is elsewhere it is recommended to include a `rel` of `canonical` from `/collections/{collectionId}` to that location. - -## Conformance - -Any implementation that provides the STAC Collection functionality described above must add `http://stacspec.org/spec/api/1.0.0-beta.3/collections`, -the conformance URI, to the `conformsTo` JSON at the landing page. - -The core STAC landing page (`/`) must also include a link with a `rel` of `data` that links to the `/collections` endpoint. - -**NOTE**: *When this aligns with OGC API - Common it will also need to add it to the `/conformance` endpoint.* diff --git a/collections/openapi.yaml b/collections/openapi.yaml index 3aa23810..edd40ae3 100644 --- a/collections/openapi.yaml +++ b/collections/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: STAC API - Collections - version: '1.0.0-beta.3' + version: '1.0.0-beta.4' description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API - Core specification. This is a subset of the STAC API - Collections specification. @@ -38,13 +38,13 @@ paths: schema: $ref: '../core/openapi.yaml#/components/schemas/landingPage' example: - stac_version: 1.0.0-beta.3 + stac_version: 1.0.0-beta.4 type: Catalog id: sentinel title: Copernicus Sentinel Imagery description: Catalog of Copernicus Sentinel 1 and 2 imagery. conformsTo: - - 'https://api.stacspec.org/v1.0.0-beta.3/core' + - 'https://api.stacspec.org/v1.0.0-beta.4/core' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson' diff --git a/core/README.md b/core/README.md index c32cfbe9..e23a853f 100644 --- a/core/README.md +++ b/core/README.md @@ -5,9 +5,9 @@ - [Example Landing Page for STAC API - Core](#example-landing-page-for-stac-api---core) - [Extensions](#extensions) -- **OpenAPI specification:** [openapi.yaml](openapi.yaml) describes the core endpoints ([rendered version](https://api.stacspec.org/v1.0.0-beta.3/core)), +- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.4/core)), and [commons.yaml](commons.yaml) is the OpenAPI version of the core [STAC spec](../stac-spec) JSON Schemas. -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Dependencies**: None @@ -48,20 +48,25 @@ API endpoints from OAFeat or STAC API to be implemented, so the following links ## Link Relations -The following Link relations should exist in the Landing Page (root). +The following Link relations shall exist in the Landing Page (root). | **rel** | **href** | **From** | **Description** | | -------------- | -------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `root` | `/` | STAC Core | The root URI | | `self` | `/` | OAFeat | Self reference, same as root URI | -| `service-desc` | `/api` (recommended) | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API | -| `child` | various | STAC Core | The child STAC Catalogs & Collections. Provides curated paths to get to STAC Collection and Item objects | +| `service-desc` | `/api` | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API. The path for this endpoint is only recommended to be `/api`, but may be another path. | -Additionally, a `service-doc` endpoint is recommended. +A `service-doc` endpoint is recommended, but not required. | **rel** | **href** | **From** | **Description** | | ------------- | ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `service-doc` | `/api.html` (recommended) | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service | +| `service-doc` | `/api.html` | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service. The path for this endpoint is only recommended to be `/api.html`, but may be another path. | + +Additionally, `child` relations may exist to individual catalogs and collections. + +| **rel** | **href** | **From** | **Description** | +| -------------- | -------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `child` | various | STAC Core | The child STAC Catalogs & Collections. Provides curated paths to get to STAC Collection and Item objects | It is also valid to have `item` links from the landing page, but most STAC API services are used to serve up a large number of features, so they typically @@ -81,8 +86,9 @@ the [overview](../overview.md#example-landing-page) document. "id": "example-stac", "title": "A simple STAC API Example", "description": "This Catalog aims to demonstrate the a simple landing page", + "type": "Catalog", "conformsTo" : [ - "https://api.stacspec.org/v1.0.0-beta.3/core" + "https://api.stacspec.org/v1.0.0-beta.4/core" ], "links": [ { diff --git a/core/commons.yaml b/core/commons.yaml index c744e2f3..e42fe618 100644 --- a/core/commons.yaml +++ b/core/commons.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Commons description: This is the OpenAPI version of the core STAC spec JSON Schemas. - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: responses: diff --git a/core/openapi.yaml b/core/openapi.yaml index eeb4d1f8..4d15443a 100644 --- a/core/openapi.yaml +++ b/core/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: STAC API - Core - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API - Core specification. Any service that implements this endpoint to allow discovery of @@ -63,7 +63,7 @@ components: title: Copernicus Sentinel Imagery description: Catalog of Copernicus Sentinel 1 and 2 imagery. conformsTo: - - 'https://api.stacspec.org/v1.0.0-beta.3/core' + - 'https://api.stacspec.org/v1.0.0-beta.4/core' links: - href: 'http://data.example.org/' rel: self diff --git a/extensions.md b/extensions.md index 88b8a75e..3e6f65c4 100644 --- a/extensions.md +++ b/extensions.md @@ -66,23 +66,34 @@ Each extension has its own conformance URI, which is used in the `conformsTo` re the service supports. This are listed at the top of each extension description, but the full table is given here for ease of reference. - [Fields](item-search/README.md#fields) - - + - + - - [Filter](item-search/README.md#filter) - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - - [Context](item-search/README.md#context) - - + - + - - [Sort](item-search/README.md#sort) - - + - + - - [Transaction](ogcapi-features/extensions/transaction/README.md) - - + - - [Items and Collections API Version](ogcapi-features/extensions/version/README.md) - - + - - [Query](item-search/README.md#query) - - + - ## Third-party / vendor extensions @@ -95,11 +106,12 @@ Please contact a STAC maintainer or open a Pull Request to add your extension to | Name | Scope | Description | Vendor | | ------------------------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------- | ---------------------------------------------- | | [Free-text Search](https://github.com/cedadev/stac-freetext-search) | [Item Search](item-search/) request | Adds `q` parameter and free-text search against item properties | [CEDA, STFC, UKRI](https://github.com/cedadev) | +| [Context Collections](https://github.com/cedadev/stac-context-collections) | [Item Search](item-search/) request | Adds a `collections` keyword to the [context](https://github.com/radiantearth/stac-api-spec/tree/master/fragments/context) extension response. | [CEDA, STFC, UKRI](https://github.com/cedadev) | ## Creating new extensions Creating new extensions requires creating an OpenAPI fragment to define it, along with a README markdown file that gives -an overview of the functionality. In the README a conformance URI should be provided, so clients can use it to tell if +an overview of the functionality. In the README, a conformance URI should be provided, so clients can use it to tell if a service has the indicated functionality. It is also recommended to note the 'extension maturity', as defined above, so others can know how widely it is used. diff --git a/fragments/context/README.md b/fragments/context/README.md index 56589304..1564f82c 100644 --- a/fragments/context/README.md +++ b/fragments/context/README.md @@ -1,7 +1,9 @@ # STAC API - Context Fragment - **OpenAPI specification:** [openapi.yaml](openapi.yaml) -- **Conformance Class:** +- **Conformance Classes:** + - Item Search binding: + - STAC Features binding: - **Fragment [Maturity Classification](../../extensions.md#extension-maturity):** Pilot - **Dependents:** - [Item Search](../../item-search) @@ -9,11 +11,14 @@ This extension is intended to augment the core [ItemCollection](../itemcollection/README.md) object when the ItemCollection is the result of a search, for example, from calling the `/search` API endpoint. -**Note**: *This fragment is currently scoped to just the STAC-specific functionality such as [STAC Item Search](../../item-search). -OGC API has their own way returning `numberMatched` and `numberReturned` at the top level, instead of in a context -object. We are hoping to [align](https://github.com/opengeospatial/ogcapi-common/issues/82), but until then it -is recommended to use STAC Context in the cross-collection `search` endpoint, and follow the OGC API way when -implementing OGC API - Features.* +This fragment may be bound to either or both of +[Item Search](../../item-search) (`/search` endpoint) or +[STAC Features](../../ogcapi-features) (`/collections/{collection_id}/items` endpoint) by +advertising the relevant conformance class. + +**Note**: OGC API Features - Part 1 has its own way returning `numberMatched` and `numberReturned` at the top level, instead of in a context +object. We are hoping to [align](https://github.com/opengeospatial/ogcapi-common/issues/82), but until then, it +is required to implement both when implementing STAC Features. - [Example](examples/example.json) - [JSON Schema](json-schema/schema.json) diff --git a/fragments/context/openapi.yaml b/fragments/context/openapi.yaml index 42a4ca2d..8745c2d1 100644 --- a/fragments/context/openapi.yaml +++ b/fragments/context/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Context description: Adds search related metadata (context) to GeoJSON Responses. - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: schemas: diff --git a/fragments/fields/README.md b/fragments/fields/README.md index 76f18fce..5912602e 100644 --- a/fragments/fields/README.md +++ b/fragments/fields/README.md @@ -1,14 +1,22 @@ # STAC API - Fields Fragment - **OpenAPI specification:** [openapi.yaml](openapi.yaml) -- **Conformance Class:** +- **Conformance Classes:** + - Item Search binding: + - STAC Features binding: - **Fragment [Maturity Classification](../../extensions.md#extension-maturity):** Pilot - **Dependents:** - [Item Search](../../item-search) + - [STAC Features](../../ogcapi-features) -STAC API by default returns everything within an item. But Item objects can have hundreds of fields, or incredibly large +STAC API by default returns every attribute in an item. However, Item objects can have hundreds of fields, or incredibly large geometries, and even smaller Item objects can get big when millions are requested but not all information is used. This -fragment provides a mechanism for clients to request that servers to explicitly include or exclude certain fields. +fragment provides a mechanism for clients to request that servers to explicitly include or exclude certain fields. + +This fragment may be bound to either or both of +[Item Search](../../item-search) (`/search` endpoint) or +[STAC Features](../../ogcapi-features) (`/collections/{collection_id}/items` endpoint) by +advertising the relevant conformance class. When used in a POST request with `Content-Type: application/json`, this adds an attribute `fields` with an object value to the core JSON search request body. The `fields` object contains two attributes with string array @@ -30,9 +38,9 @@ polygons can be very large when reprojected to EPSG:4326, as in the case of a hi Implementations are also not required to implement semantics for nested values whereby one can include an object, but exclude attributes of that object, e.g., include `properties` but exclude `properties.datetime`. -No error should be returned if a specified field has no value for it in the catalog. For example, if the attribute +No error must be returned if a specified field has no value for it in the catalog. For example, if the attribute "properties.eo:cloud_cover" is specified but there is no cloud cover value for an Item or the API does not even -support the EO Extension, a successful HTTP response should be returned and the Item entities will not contain that +support the EO Extension, a successful HTTP response must be returned and the Item entities will not contain that attribute. If no `fields` are specified, the response is **must** be a valid [ItemCollection](../itemcollection/README.md). If a client excludes @@ -40,7 +48,7 @@ attributes that are required in a STAC Item, the server may return an invalid ST and `geometry` are excluded, the entity will not even be a valid GeoJSON Feature, or if `bbox` is excluded then the entity will not be a valid STAC Item. -Implementations may return attributes not specified, e.g., id, but should avoid anything other than a minimal entity +Implementations may return attributes not specified, e.g., id, but must avoid anything other than a minimal entity representation. ## Include/Exclude Semantics @@ -55,7 +63,7 @@ of default properties attributes should be kept to a minimum. the `include` attributes (set difference operation). This will result in an entity that is not a valid Item if any of the excluded attributes are in the default set of attributes. 4. If both `include` and `exclude` attributes are specified, semantics are that a field must be included and **not** -excluded. E.g., if `properties` is included and `properties.datetime` is excluded, then `datetime` should not appear +excluded. E.g., if `properties` is included and `properties.datetime` is excluded, then `datetime` must not appear in the attributes of `properties`. ## Examples diff --git a/fragments/fields/openapi.yaml b/fragments/fields/openapi.yaml index e0ae8172..3c3397ef 100644 --- a/fragments/fields/openapi.yaml +++ b/fragments/fields/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Fields description: Adds parameter to control which fields are returned in the response. - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: parameters: diff --git a/fragments/filter/README.md b/fragments/filter/README.md index bfc53406..5fb7d386 100644 --- a/fragments/filter/README.md +++ b/fragments/filter/README.md @@ -2,20 +2,19 @@ - **OpenAPI specification:** [openapi.yaml](openapi.yaml) - **Conformance Classes:** - - Filter: - - Item Search Filter: - - CQL Text: - - CQL JSON: - - Basic CQL: - - Basic Spatial Operators: - - Basic Temporal Operators: - - Enhanced Comparison Operators: - - Enhanced Spatial Operators: - - Enhanced Temporal Operators: - - Functions: - - Arithmetic: - - Arrays: - - Queryable Second Operand: + - Filter: + - Item Search Filter: + - CQL Text: + - CQL JSON: + - Basic CQL: + - Advanced Comparison Operators: + - Basic Spatial Operators: + - Spatial Operators: + - Temporal Operators: + - Custom Functions: + - Arithmetic Expressions: + - Array Operators: + - Property-Property Comparisons: - **Extension [Maturity Classification](../../extensions.md#extension-maturity):** Pilot - **Dependents:** - [Item Search](../../item-search) @@ -48,23 +47,29 @@ - [Example 6: Temporal](#example-6-temporal) - [Example 6: ANYINTERACTS cql-text (GET)](#example-6-anyinteracts-cql-text-get) - [Example 6: ANYINTERACTS cql-json (POST)](#example-6-anyinteracts-cql-json-post) - - [Example 6: Spatial](#example-6-spatial) - - [Example 6: INTERSECTS cql-text (GET)](#example-6-intersects-cql-text-get) - - [Example 6: INTERSECTS cql-json (POST)](#example-6-intersects-cql-json-post) + - [Example 7: Spatial](#example-7-spatial) + - [Example 7: INTERSECTS cql-text (GET)](#example-7-intersects-cql-text-get) + - [Example 7: INTERSECTS cql-json (POST)](#example-7-intersects-cql-json-post) + - [Example 8: Spatial Disjunction](#example-8-spatial-disjunction) + - [Example 8: INTERSECTS cql-text (GET)](#example-8-intersects-cql-text-get) + - [Example 8: INTERSECTS cql-json (POST)](#example-8-intersects-cql-json-post) + - [Example 9: Using IS NULL](#example-9-using-is-null) + - [Example 9: cql-text (GET)](#example-9-cql-text-get) + - [Example 9: cql-json (POST)](#example-9-cql-json-post) ## Overview The Filter extension provides an expressive mechanism for searching based on Item attributes. This extension references behavior defined in the -[OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)](https://portal.ogc.org/files/96288) -specification. As of July 2021, this specification is in draft status. The only major anticipated change before final -is to the division of behavior among conformance classes, as described -in the [Conformance Classes](#conformance-classes) section. While this makes implementing this spec somewhat of a moving -target, implementers are encouraged to move ahead with support with the expectation that they will be able to precisely -advertise behavior through conformance classes prior to STAC API 1.0.0 final. - -OAFeat Part 3 CQL formally defines the syntax of "CQL2" as both a text format (cql-text) as an ABNF grammar +[OGC API - Features - Part 3: Filtering and the Common Query Language (CQL2)](https://github.com/opengeospatial/ogcapi-features/tree/master/extensions/cql) +specification. As of August 2021, this specification is in draft status. Several behaviors have changed since the +last published [draft](https://portal.ogc.org/files/96288), so this spec references the latest revision in the +[spec's GitHub repo](https://github.com/opengeospatial/ogcapi-features/tree/master/extensions/cql). There are no +major anticipated changes, so implementers are encouraged to move ahead with implementation, and to simply be +aware that minor changes may need to be made in the future. + +OAFeat Part 3 CQL2 formally defines the syntax of "CQL2" as both a text format (cql-text) as an ABNF grammar (largely similar to the BNF grammar in the General Model for CQL) and a JSON format (cql-json) as a JSON Schema and OpenAPI schema, and provides a precise natural language description of the declarative semantics. The CQL Text format has long-standing use within @@ -74,7 +79,7 @@ OGC CQL Text has been previously described in [OGC Filter Encoding](https://www. (including a BNF grammar in Annex B). The CQL JSON format is newly-defined, but also not expected to change before final. -It should be noted that the "CQL" referred to here is "CQL2" defined in OGC API Features Part 3 CQL. This is a related, but +It should be noted that the "CQL" referred to here is "CQL2" defined in OGC API - Features - Part 3. This is a related, but different language to the "classic" OGC CQL defined in the General Model. CQL is also **not** referencing or related two other "CQL" languages, the [SRU (Search/Retrieve via URL) Contextual Query Language](https://www.loc.gov/standards/sru/cql/index.html) (formerly @@ -96,92 +101,80 @@ However, it does not contain a formalized way to filter based on arbitrary field no way to express the filter "item.properties.eo:cloud_cover is less than 10". It also does not have a way to logically combine multiple spatial or temporal filters. -## Filter expressiveness +## Filter expressiveness This extension expands the capabilities of Item Search and the OAFeat Items resource with -[OAFeat Part 3 CQL](https://portal.ogc.org/files/96288) -by providing an expressive query language to construct more complex filter predicates. The operators are similar to -those provided by SQL. The Basic CQL conformance class requires the logical operators `AND`, `OR`, and `NOT`; -the comparison operators `=`, `<`, `<=`, `>`, `>=`; and the `IS NULL` operator. Other conformance classes add additional -filtering capabilities. - -The `ANYINTERACTS` operator has effectively the same semantics as the `datetime` parameter -in Item Search. +[OAFeat Part 3 CQL2](https://portal.ogc.org/files/96288) +by providing an expressive query language to construct more complex filter predicates using operators that are similar to +those provided by SQL. This extension also supports the Queryables mechanism that allows discovery of what Item fields can be used in +predicates. -CQL enables these types of queries: +CQL enables more expressive queries than supported by STAC API Item Search. These include: - Use of Item Property values in predicates (e.g., `item.properties.eo:cloud_cover`), using comparison operators -- Items whose `datetime` values are in the month of August of the years 2017-2021, using OR and ANYINTERACTS +- Items whose `datetime` values are in the month of August of the years 2017-2021, using OR and datetime comparisons - Items whose `geometry` values intersect any one of several Polygons, using OR and INTERSECTS - Items whose `geometry` values intersect one Polygon, but do not intersect another one, using AND, NOT, and INTERSECTS -This extension also supports the Queryables mechanism that allows discovery of what Item fields can be used in -predicates. - ## Conformance Classes -OAFeat CQL defines several conformance classes that allow implementers to create compositions of +OAFeat Part 3 CQL defines several conformance classes that allow implementers to create compositions of functionality that support whatever expressiveness they need. This allows implementers to incrementally support CQL syntax, without needing to implement a huge spec all at once. Some implementers choose not to incur the cost of implementing functionality they do not need or may not be able to implement functionality that is not supported by their underlying datastore, e.g., Elasticsearch does not support the spatial predicates required by the -Enhanced Spatial Operators conformance class. +Spatial Operators conformance class, only the `intersects` operator in the Basic Spatial Operators class. -The precise decomposition of the OAFeat conformance classes is still a work in progress -(see [ogcapi-features/issues/579](https://github.com/opengeospatial/ogcapi-features/issues/579)). -The STAC API Filter Extension reuses the definitions in OAFeat CQL, but divides them into different conformance classes -that better fit the use cases of STAC API. This extension uses conformance classes with a prefix of -`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:`. We hope the conformance -classes defined here and in OGC API Features Part 3 will re-align at some point but, for now, they do not. +The precise decomposition of the OAFeat conformance classes is still a work in progress, but is being finalized +rapidly (see [ogcapi-features/issues/579](https://github.com/opengeospatial/ogcapi-features/issues/579)). +The STAC API Filter Extension reuses the definitions and conformance classes in OAFeat CQL, +adding only the Item Search Filter conformance class +(`https://api.stacspec.org/v1.0.0-beta.4/item-search#filter:item-search-filter`) to bind +the CQL filter behavior to the Item Search resource. The implementation **must** support these conformance classes: -- Filter (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:filter`) defines the Queryables mechanism and +- Filter (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter`) defines the Queryables mechanism and parameters `filter-lang`, `filter-crs`, and `filter`. -- Basic CQL (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-cql`) defines the basic operations allowed in +- Basic CQL (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/basic-cql`) defines the basic operations allowed in the query language used for the `filter` parameter defined by Filter. This includes logical operators (`AND`, `OR`, `NOT`), - comparison operators (`=`, `<`, `<=`, `>`, `>=`), and `IS NULL`. -- Item Search Filter (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:item-search-filter`) binds the Filter and + comparison operators (`=`, `<>`, `<`, `<=`, `>`, `>=`), and `IS NULL`. The comparison operators are allowed against string, numeric, boolean, + and datetime types. +- Item Search Filter (`https://api.stacspec.org/v1.0.0-beta.4/item-search#filter:item-search-filter`) binds the Filter and Basic CQL conformance classes to apply to the Item Search endpoint (`/search`). This class is the correlate of the OAFeat CQL Features Filter class that binds Filter and Basic CQL to the Features resource (`/collections/{cid}/items`). -It is **recommended** that the implementation also support the Basic Spatial Operators and Basic Temporal Operators classes: - -- Basic Spatial Operators (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-spatial-operators`) - defines the `INTERSECTS` predicate -- Basic Temporal Operators: (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-temporal-operators`) - defines the `ANYINTERACTS` predicate - -Additionally, the implementation **must** support at least one of the "CQL Text" or "CQL JSON" conformance classes that define +The implementation **must** support at least one of the "CQL Text" or "CQL JSON" conformance classes that define the CQL format used in the filter parameter: -- CQL Text (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:cql-text`) defines that the CQL Text format is supported by Item Search. -- CQL JSON (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:cql-json`) defines that the CQL JSON format is supported by Item Search +- CQL Text (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/cql-text`) defines that the CQL Text format is supported by Item Search +- CQL JSON (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/cql-json`) defines that the CQL JSON format is supported by Item Search If both are advertised as being supported, it is only required that both be supported for GET query parameters, and that only that CQL JSON be supported for POST JSON requests. It is recommended that clients use CQL Text in GET requests and CQL JSON in POST requests. -The Filter Extension defines support for implementing the following conformance -classes. Implementation of these is often limited by the -operations supported by the implementation's datastore, for example, Elasticsearch does not support the spatial -operations required by the Enhanced Spatial Operators. If implemented for Item Search, the conformance class -URI should follow the same pattern relative to OAFeat CQL. - -- Enhanced Comparison Operators - (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:enhanced-comparison-operators`) defines the `LIKE`, - `BETWEEN`, and `IN` operators. It is **recommended** to implement this class. -- Enhanced Spatial Operators - (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:enhanced-spatial-operators`) defines the - same operators as OAF Part 3 CQL Enhanced Spatial Operators. -- Enhanced Temporal Operators - (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:enhanced-temporal-operators`) defines the +For additional capabilities, the following classes can be implemented: +- Advanced Comparison Operators + (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/advanced-comparison-operators`) defines the `LIKE`, + `BETWEEN`, and `IN` operators. Note: this conformance class does **not** require implementing the + `lower` and `upper` functions as defined in the latest OAFeat CQL spec, as these will soon be + removed from the corresponding OAFeat CQL conformance class. +- Basic Spatial Operators (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/basic-spatial-operators`) defines the `INTERSECTS` predicate. +- Spatial Operators + (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/spatial-operators`) defines the + same operators as OAF Part 3 CQL Advanced Spatial Operators. +- Temporal Operators + (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/temporal-operators`) defines the same operators as OAF Part 3 CQL Enhanced Temporal Operators. -- Functions (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:functions`) defines the same operators as OAF Part 3 CQL Functions. -- Arithmetic: (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:arithmetic`) defines the same operators as OAF Part 3 CQL Arithmetic. -- Arrays: (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:arrays`) defines the same operators as OAF Part 3 CQL Arrays. -- Queryable Second Operand: (`https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:queryable-second-operand`) allows the - use of queryables (e.g., properties) in any position of a clause, not just in the first position. This allows +- Custom Functions (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/functions`) defines the + same operators as OAF Part 3 CQL Custom Functions. +- Arithmetic Expressions: (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/arithmetic`) defines + the same operators as OAF Part 3 CQL Arithmetic Expressions. +- Array Operators: (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/array-operators`) + defines the same operators as OAF Part 3 CQL Array Operators. +- Property-Property Comparisons: (`http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/property-property`) allows the + use of queryables (e.g., properties) in both positions of a clause, not just in the first position. This allows predicates like `property1 == property2` be expressed, whereas the Basic CQL conformance class only requires comparisons against literal values. @@ -195,10 +188,11 @@ to the Features resource is not supported, as POST is used by the It recommended that implementers start with fully implementing only a subset of functionality. A good place to start is implementing only the Basic CQL conformance class of logical and comparison operators, defining a static Queryables -schema with no queryables advertised, and only implementing CQL Text. Following from that can be support for -INTERSECTS and ANYINTERACTS, defining a static Queryables schema with only the basic Item properties, and also +schema with no queryables advertised and the `additionalProperties` field set to `true`, and +only implementing CQL Text. Following from that can be support for +INTERSECTS, defining a static Queryables schema with only the basic Item properties, and implementing CQL JSON. From there, other comparison operators can be implemented and a more -dynamic Queryables schema (if desired). +dynamic Queryables schema. Formal definitions and grammars for CQL can be found here: @@ -230,16 +224,15 @@ not compliant with this extension. ## Queryables -The Queryables mechanism allows a client to discover what variable terms are available for use when writing filter -expressions. These variables can be defined per-collection, and the intersection of these variables over all collections is what -is available for filtering when there are no collection restrictions. These queryables are the only variables that may be used -in filter expressions, and if any variable is used in expression that is not defined as a queryable and error should be +The Queryables mechanism allows a client to discover what terms are available for use when writing filter +expressions. These terms can be defined per-collection, and the intersection of these terms over all collections is what +is available for filtering when there are no collection restrictions. By default, these queryables are the only terms that may be used +in filter expressions, and if any term is used in expression that is not defined as a queryable and error must be returned according to OAFeat Part 3. It is recognized that this is a severe restriction in STAC APIs that have highly variable -and dynamic content. It is possible that this will change in the OAFeat Part 3 spec, see -this [issue](https://github.com/opengeospatial/ogcapi-features/issues/582). For now, implementers may choose to allow -fully-qualified property -names not advertised in queryables (e.g., `properties.eo:cloud_cover`, in anticipation that there be some -mechanism to explicitly allow or advertise this in the future. +and dynamic content, so this behavior may be modified by setting the `additionalProperties` attribute in the +queryables definition to `true`. As such, any syntactically-valid term for a property will be accepted, and the +matching semantics are such that, if an Item does not have an attribute by that name, the value is assumed to be +`null`. It is recommended to use fully-qualified property names (e.g., `properties.eo:cloud_cover`). Queryables are advertised via a JSON Schema document retrieved from the `/queryables` endpoint. This endpoint at the root retrieves queryables that apply to all collections. When used as a subresource of the collection resource @@ -273,7 +266,8 @@ definitions for STAC Items should include at least the fields id, collection, ge "description" : "Datetime", "$ref": "https://schemas.stacspec.org/v1.0.0/item-spec/json-schema/datetime.json#/properties/datetime" } - } + }, + "additionalProperties": true } ``` @@ -287,21 +281,21 @@ The Landing Page endpoint (`/`) will have a Link with rel `http://www.opengis.ne the endpoint `/queryables`. Additionally, each Collection resource will have a Link to the queryables resource for that collection, e.g., `/collections/collection1/queryables`. -The queryables endpoint returns a JSON Schema describing the names and types variables that may be used in filter expressions. +The queryables endpoint returns a JSON Schema describing the names and types of terms that may be used in filter expressions. This response is defined in JSON Schema because it is a well-specified typed schema, but it is not used for validating a JSON -document derived from it. This schema defines the variables that may be used in a CQL filter. +document derived from it. This schema defines the terms that may be used in a CQL filter. -These queryable variables are mapped by the service to filter Items. For example, the service may define a queryable with the +These queryable terms are mapped by the service to filter Items. For example, the service may define a queryable with the name "eo:cloud_cover" that can be used in a CQL expression like `eo:cloud_cover <= 10`, with the semantics that only Items where the `properties.eo:cloud_cover` value was <= 10 would match the filter. The server would then translate this into an appropriate query for the data within its datastore. Queryables can be static or dynamically derived. For example, `cloud_cover` might be specified to have a value 0 to 100 or a field -may have a set of enumerated values dynamically determined by an aggreation at runtime. This schema can be used by a UI or +may have a set of enumerated values dynamically determined by an aggregation at runtime. This schema can be used by a UI or interactive client to dynamically expose to the user the fields that are available for filtering, and provide a precise group -of options for the values of these variables. +of options for the values of these terms. -Queryables can also be used to advertise synthesized property values. The only requirement in CQL is that the property have a type +Queryables can also be used to advertise "synthesized" property values. The only requirement in CQL is that the property have a type and evaluate to literal value of that type or NULL. For example, a filter like "Items must have an Asset with an eo:band with the common_name of 'nir'" can be expressed. A Queryable `assets_bands` could be defined to have a type of array of string and have the semantics that it contains all of `common_name` values across all assets and bands for an Item. This could then be @@ -321,7 +315,8 @@ in STAC API by the Filter Extension. In this case, the queryables endpoint (`/qu "title" : "Queryables for Example STAC API", "description" : "Queryable names for the example STAC API Item Search filter.", "properties" : { - } + }, + "additionalProperties": true } ``` @@ -341,7 +336,7 @@ supported, the server must return a 400 error if `filter-lang=cql-text`. ## Interaction with Endpoints -In an implementation that supports several operator classes, the Landing Page (`/`) should return a document including +In an implementation that supports several operator classes, the Landing Page (`/`) must return a document including at least these values: ```json @@ -352,20 +347,19 @@ at least these values: "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson", - "http://www.opengis.net/spec/ogcapi_common-2/1.0/req/collections", + "http://www.opengis.net/spec/ogcapi_common-2/1.0/conf/collections", - "http://api.stacspec.org/v1.0.0-beta.3/core", - "http://api.stacspec.org/v1.0.0-beta.3/stac-search", - "http://api.stacspec.org/v1.0.0-beta.3/stac-response", + "http://api.stacspec.org/v1.0.0-beta.4/core", + "http://api.stacspec.org/v1.0.0-beta.4/stac-search", + "http://api.stacspec.org/v1.0.0-beta.4/stac-response", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:filter", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:features-filter", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-cql", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:cql-text", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:cql-json", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-spatial-operators", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:basic-temporal-operators", - "https://api.stacspec.org/v1.0.0-beta.3/item-search#filter:enhanced-comparison-operators" + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/filter", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/features-filter", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/basic-cql", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/cql-text", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/cql-json", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/basic-spatial-operators", + "http://www.opengis.net/spec/ogcapi-features-3/1.0/conf/advanced-comparison-operators" ], "links": [ @@ -384,6 +378,7 @@ at least these values: ], "stac_extensions": [], "stac_version": "1.0.0", + "type": "Catalog", } ``` @@ -427,7 +422,8 @@ The Queryables endpoint (`/queryables`) returns something like the following: "description" : "Asset eo:bands common names", "$ref": "https://stac-extensions.github.io/eo/v1.0.0/schema.json#/properties/eo:bands/common_name" } - } + }, + "additionalProperties": true } ``` @@ -450,10 +446,13 @@ These parameters/fields must be supported by the STAC Item Search endpoint and O ## Examples -Note: the GET examples with query parameters are unescaped to make them easier to read. +Note: the GET examples with query parameters are unescaped to make them easier to read. + +The GET examples are assuming a call to `GET /search` and the POST examples are assuming a +call to `POST /search`. The parameter `filter-crs` always defaults to `http://www.opengis.net/def/crs/OGC/1.3/CRS84` for a STAC API, so is not shown -in any of these examples. +in any of these examples. ### Example 1 @@ -464,8 +463,8 @@ This example uses the queryables definition in (Interaction with Endpoints)(#int Note that `filter-lang` defaults to `cql-text` in this case. The parameter `filter-crs` defaults to `http://www.opengis.net/def/crs/OGC/1.3/CRS84` for a STAC API. -```javascript -GET /search?filter=id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collection='landsat8_l1tp' +```http +filter=id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collection='landsat8_l1tp' ``` #### Example 1: POST with cql-json @@ -473,19 +472,12 @@ GET /search?filter=id='LC08_L1TP_060247_20180905_20180912_01_T1_L1TP' AND collec Note that `filter-lang` defaults to `cql-json` in this case. The parameter `filter-crs` defaults to `http://www.opengis.net/def/crs/OGC/1.3/CRS84` for a STAC API. -```javascript -POST /search -{ +```json +{ "filter": { "and": [ - "eq": [ - { "property": "id" }, - "LC08_L1TP_060247_20180905_20180912_01_T1_L1TP" - ], - "eq": [ - { "property": "collection" }, - "landsat8_l1tp" - ] + { "eq": [ { "property": "id" }, "LC08_L1TP_060247_20180905_20180912_01_T1_L1TP" ] }, + { "eq": [ { "property": "collection" }, "landsat8_l1tp" ] } ] } } @@ -500,55 +492,50 @@ OGC API Features filters only operate against a single collection already. #### Example 2: GET with cql-text -```javascript -GET /search?filter=collection = 'landsat8_l1tp' +```http +filter=collection = 'landsat8_l1tp' AND gsd <= 30 - AND eo:cloud_cover <= 10 - AND datetime ANYINTERACTS 2021-04-08T04:39:23Z/2021-05-07T12:27:57Z - AND INTERSECTS(geometry, POLYGON((43.5845 -79.5442, 43.6079 -79.4893, 43.5677 -79.4632, 43.6129 -79.3925, 43.6223 -79.3238, 43.6576 -79.3163, 43.7945 -79.1178, 43.8144 -79.1542, 43.8555 -79.1714, 43.7509 -79.6390, 43.5845 -79.5442)) + AND eo:cloud_cover <= 10 + AND datetime >= "2021-04-08T04:39:23Z" + AND datetime <= "2021-05-07T12:27:57Z" + AND INTERSECTS(geometry, POLYGON((43.5845 -79.5442, 43.6079 -79.4893, 43.5677 -79.4632, 43.6129 -79.3925, 43.6223 -79.3238, 43.6576 -79.3163, 43.7945 -79.1178, 43.8144 -79.1542, 43.8555 -79.1714, 43.7509 -79.6390, 43.5845 -79.5442)) ``` #### Example 2: POST with cql-json -```javascript -POST /search -{ +```json +{ "filter-lang": "cql-json", "filter": { "and": [ - "eq": [ - { "property": "collection" }, - "landsat8_l1tp" - ], - "lte": [ - { "property": "eo:cloud_cover" }, - "10" - ], - "anyinteracts": [ - { "property": "datetime" }, - [ "2021-04-08T04:39:23Z", "2021-05-07T12:27:57Z" ] - ], - "intersects": [ - { "property": "geometry" }, - { - "type": "Polygon", - "coordinates": [ + { "eq": [ { "property": "collection" }, "landsat8_l1tp" ] }, + { "lte": [ { "property": "eo:cloud_cover" }, "10" ] }, + { "gte": [ { "property": "datetime" }, "2021-04-08T04:39:23Z" ] }, + { + "intersects": [ + { + "property": "geometry" + }, + { + "type": "Polygon", + "coordinates": [ [ - [43.5845,-79.5442], - [43.6079,-79.4893], - [43.5677,-79.4632], - [43.6129,-79.3925], - [43.6223,-79.3238], - [43.6576,-79.3163], - [43.7945,-79.1178], - [43.8144,-79.1542], - [43.8555,-79.1714], - [43.7509,-79.6390], - [43.5845,-79.5442] + [43.5845, -79.5442], + [43.6079, -79.4893], + [43.5677, -79.4632], + [43.6129, -79.3925], + [43.6223, -79.3238], + [43.6576, -79.3163], + [43.7945, -79.1178], + [43.8144, -79.1542], + [43.8555, -79.1714], + [43.7509, -79.6390], + [43.5845, -79.5442] ] - ] - } - ] + ] + } + ] + } ] } } @@ -584,14 +571,13 @@ This queryables JSON Schema is used in these examples: #### Example 3: GET with cql-text -```javascript -GET /search?filter=prop1 = prop2 +```http +filter=prop1 = prop2 ``` #### Example 3: POST with cql-json -```javascript -POST /search +```json { "filter-lang": "cql-json", "filter": { @@ -697,34 +683,21 @@ a tiny sliver of data. #### Example 4: AND cql-text (GET) -```javascript -/search?filter=sentinel:data_coverage > 50 AND eo:cloud_cover < 10 +```http +filter=sentinel:data_coverage > 50 AND eo:cloud_cover < 10 ``` #### Example 4: AND cql-json (POST) ```json { - "filter": { - "and": [ - { - "gt": [ - { - "property": "sentinel:data_coverage" - }, - 50 - ] - }, - { - "lt": [ - { - "property": "eo:cloud_cover" - }, - 10 - ] - } - ] - } + "filter-lang": "cql-json", + "filter": { + "and": [ + { "gt": [ { "property": "sentinel:data_coverage" }, 50 ] }, + { "lt": [ { "property": "eo:cloud_cover" }, 10 ] } + ] + } } ``` @@ -737,30 +710,21 @@ This uses the same queryables as Example 4. #### Example 5: OR cql-text (GET) -```javascript -/search?filter=sentinel:data_coverage > 50 OR eo:cloud_cover < 10 +```http +filter=sentinel:data_coverage > 50 OR eo:cloud_cover < 10 ``` #### Example 5: OR cql-json (POST) ```json { + "filter-lang": "cql-json", "filter": { "or": [ - { - "gt": [ - { "property": "sentinel:data_coverage" }, - 50 - ] - }, - { - "lt": [ - { "property": "eo:cloud_cover" }, - 10 - ] - } - ] - } + { "gt": [ { "property": "sentinel:data_coverage" }, 50 ] }, + { "lt": [ { "property": "eo:cloud_cover" }, 10 ] } + ] + } } ``` @@ -768,56 +732,139 @@ This uses the same queryables as Example 4. This uses the same queryables as Example 4. -The only temporal operator required is `ANYINTERACTS`, which follows the same semantics as the existing -`datetime` parameter. This is effectively that the datetime or interval operands have any overlap between them. +The only temporal operator required is `ANYINTERACTS`. This is effectively that the datetime or interval operands +have any overlap between them. #### Example 6: ANYINTERACTS cql-text (GET) -```javascript -/search?filter=datetime ANYINTERACTS 2020-11-11 +```http +filter=datetime ANYINTERACTS 2020-11-11T00:00:00Z/2020-11-12T00:00:00Z ``` #### Example 6: ANYINTERACTS cql-json (POST) ```json { + "filter-lang": "cql-json", + "filter": { + "anyinteracts": [ + { "property": "datetime" }, + [ "2020-11-11T00:00:00Z", "2020-11-12T00:00:00Z"] + ] + } +} +``` + +### Example 7: Spatial + +The only spatial operator that must be implemented for Basic Spatial Operators +is `INTERSECTS`. This has the same semantics as the one provided +in the Item Search `intersects` parameter. The `cql-text` format uses WKT geometries and the `cql-json` +format uses GeoJSON geometries. + +#### Example 7: INTERSECTS cql-text (GET) + +```http +filter=INTERSECTS(geometry,POLYGON((-77.0824 38.7886,-77.0189 38.7886,-77.0189 38.8351,-77.0824 38.8351,-77.0824 38.7886))) +``` + +#### Example 7: INTERSECTS cql-json (POST) + +```json +{ + "filter-lang": "cql-json", "filter": { - "anyinteracts": [ - { "property": "datetime" }, - "2020-11-11" - ] + "intersects": [ + { "property": "geometry" } , + { + "type": "Polygon", + "coordinates": [[ + [-77.0824, 38.7886], [-77.0189, 38.7886], + [-77.0189, 38.8351], [-77.0824, 38.8351], + [-77.0824, 38.7886] + ]] + } + ] } } ``` -### Example 6: Spatial +### Example 8: Spatial Disjunction -The only spatial operator that must be implemented is `INTERSECTS`. This has the same semantics as the one provided -in the Item Search `intersects` parameter. The `cql-text` format uses WKT geometries and the `cql-json` format uses -GeoJSON geometries. +One limitation of the `intersects` parameter is that only a single geometry may be provided. While most +GeoJSON geometries can be combined to form a composite (e.g., multiple Polygons can be combined to form a +MultiPolygon), this is much easier to do in the query by combining `INTERSECTS` predicates with the `OR` +logical operator. -#### Example 6: INTERSECTS cql-text (GET) +#### Example 8: INTERSECTS cql-text (GET) -```javascript -/search?filter=INTERSECTS(geometry,POLYGON((-77.0824 38.7886,-77.0189 38.7886,-77.0189 38.8351,-77.0824 38.8351,-77.0824 38.7886))) +```http +filter=INTERSECTS(geometry,POLYGON((-77.0824 38.7886,-77.0189 38.7886,-77.0189 38.8351,-77.0824 38.8351,-77.0824 38.7886))) OR INTERSECTS(geometry,POLYGON((-79.0935 38.7886,-79.0290 38.7886,-79.0290 38.8351,-79.0935 38.8351,-79.0935 38.7886))) ``` -#### Example 6: INTERSECTS cql-json (POST) +#### Example 8: INTERSECTS cql-json (POST) ```json { - "filter": { - "intersects": [ - { "property": "geometry" } , - { - "type": "Polygon", - "coordinates": [[ - [-77.0824, 38.7886], [-77.0189, 38.7886], - [-77.0189, 38.8351], [-77.0824, 38.8351], - [-77.0824, 38.7886] - ]] - } + "filter": { + "or" : [ + "intersects": [ + { "property": "geometry" } , + { + "type": "Polygon", + "coordinates": [[ + [-77.0824, 38.7886], [-77.0189, 38.7886], + [-77.0189, 38.8351], [-77.0824, 38.8351], + [-77.0824, 38.7886] + ]] + } + ], + "intersects": [ + { "property": "geometry" } , + { + "type": "Polygon", + "coordinates": [[ + [-79.0935, 38.7886], [-79.0290, 38.7886], + [-79.0290, 38.8351], [-79.0935, 38.8351], + [-79.0935, 38.7886] + ]] + } + ] + ] + } +} +``` + +### Example 9: Using IS NULL + +One of the main use cases for STAC API is doing cross-collection query. Commonly, this means that items have +different sets of properties. For example, a collection of Sentinel 2 data may have a property +`sentinel:data_coverage` and a collection of Landsat 8 data may have a corresponding property +`landsat:coverage_percent`, both representing what percentage of a given gridded scene actually contains +data. However, we many also want to also include in our result items that do not have a value defined for +either of those properties. + +#### Example 9: cql-text (GET) + +```http +filter=sentinel:data_coverage > 50 OR landsat:coverage_percent < 10 OR (sentinel:data_coverage IS NULL AND landsat:coverage_percent IS NULL) +``` + +#### Example 9: cql-json (POST) + +```json +{ + "filter": { + "or": [ + { "gte": [ { "property": "sentinel:data_coverage" }, 50 ] }, + { "gte": [ { "property": "landsat:coverage_percent" }, 50 ] }, + { + "and": [ + { "isNull": { "property": "sentinel:data_coverage" } }, + { "isNull": { "property": "landsat:coverage_percent" } } ] - }, + } + ] + } } ``` diff --git a/fragments/filter/openapi.yaml b/fragments/filter/openapi.yaml index c1a331b2..be5fe32e 100644 --- a/fragments/filter/openapi.yaml +++ b/fragments/filter/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Filter description: Adds parameters to compare properties and only return the items that match - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 tags: - name: STAC API - Core diff --git a/fragments/itemcollection/README.md b/fragments/itemcollection/README.md index 5b186ccb..db69a74c 100644 --- a/fragments/itemcollection/README.md +++ b/fragments/itemcollection/README.md @@ -4,7 +4,7 @@ This document explains the structure and content of a SpatioTemporal Asset Catal An **ItemCollection** is a [GeoJSON](http://geojson.org/) [FeatureCollection](https://tools.ietf.org/html/rfc7946#section-3.3) that is augmented with [foreign members](https://tools.ietf.org/html/rfc7946#section-6) relevant to a STAC entity. -Similarly to the relationship between a GeoJSON Feature and a STAC Item, a STAC ItemCollection should be a valid GeoJSON +Similarly to the relationship between a GeoJSON Feature and a STAC Item, a STAC ItemCollection must be a valid GeoJSON FeatureCollection to allow interoperability with existing tools that support GeoJSON. Item objects are represented in JSON format and are very flexible. Any JSON object that contains all the diff --git a/fragments/itemcollection/openapi.yaml b/fragments/itemcollection/openapi.yaml index ed222885..b2295e4d 100644 --- a/fragments/itemcollection/openapi.yaml +++ b/fragments/itemcollection/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Item Collection description: The specification for a set of items, e.g. returned by a search. - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: schemas: diff --git a/fragments/query/README.md b/fragments/query/README.md index 2229092d..38a3cfb1 100644 --- a/fragments/query/README.md +++ b/fragments/query/README.md @@ -1,7 +1,7 @@ # STAC API - Query Fragment - **OpenAPI specification:** [openapi.yaml](openapi.yaml) -- **Conformance Class:** +- **Conformance Class:** - **Extension [Maturity Classification](../../extensions.md#extension-maturity):** Pilot, scheduled to be Deprecated in favor of the [Filter Extension](../filter/README.md) using [CQL](http://docs.opengeospatial.org/DRAFTS/19-079.html). - **Dependents:** - [Item Search](../../item-search) diff --git a/fragments/query/openapi.yaml b/fragments/query/openapi.yaml index fd22abc7..ccdaeabe 100644 --- a/fragments/query/openapi.yaml +++ b/fragments/query/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Query description: Adds parameter to compare properties and only return the items that match - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: parameters: diff --git a/fragments/sort/README.md b/fragments/sort/README.md index 8c61d51d..7caca4d8 100644 --- a/fragments/sort/README.md +++ b/fragments/sort/README.md @@ -1,16 +1,24 @@ # STAC API - Sort Fragment - **OpenAPI specification:** [openapi.yaml](openapi.yaml) -- **Conformance Class:** +- **Conformance Class:** + - Item Search binding: + - STAC Features binding: - **Fragment [Maturity Classification](../../extensions.md#extension-maturity):** Pilot - **Dependents:** - [Item Search](../../item-search) + - [STAC Features](../../ogcapi-features) This defines a new parameter, `sortby`, that allows the user to define fields by which to sort results. Only string, numeric, and datetime attributes of Item (`id` and `collection` only) or Item Properties (any attributes) may be used to sort results. It is not required that implementations support sorting over all attributes, but implementations should return an error when attempting to sort over a field that does not support sorting. +This fragment may be bound to either or both of +[Item Search](../../item-search) (`/search` endpoint) or +[STAC Features](../../ogcapi-features) (`/collections/{collection_id}/items` endpoint) by +advertising the relevant conformance class. + Fields may be sorted in ascending or descending order. The syntax between GET requests and POST requests with a JSON body vary. The `sortby` value is an array, so multiple sort fields can be defined which will be used to sort the data in the order provided (e.g., first by `datetime`, then by `eo:cloud_cover`). @@ -22,7 +30,7 @@ for the latest discussion.* ## HTTP GET (or POST Form) When calling a relevant endpoint using GET (or POST with `Content-Type: application/x-www-form-urlencoded` or -`Content-Type: multipart/form-data)`, a single parameter `sortby` with a comma-separated list of item field names should +`Content-Type: multipart/form-data)`, a single parameter `sortby` with a comma-separated list of item field names must be provided. The field names may be prefixed with either "+" for ascending, or "-" for descending. If no sign is provided before the field name, it will be assumed to be "+". diff --git a/fragments/sort/openapi.yaml b/fragments/sort/openapi.yaml index 7cfbf7cd..e64a2cb9 100644 --- a/fragments/sort/openapi.yaml +++ b/fragments/sort/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Sort description: Adds Parameter to control sorting of returns results. - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 paths: {} components: parameters: diff --git a/implementation.md b/implementation.md index 16f2177c..2b61cd75 100644 --- a/implementation.md +++ b/implementation.md @@ -2,6 +2,12 @@ This document describes implementation recommendations for a STAC API. +## Identifiers + +It is recommended that all items presented through a STAC API be part of a collection. STAC +allows items to not be contained in a collection, though this is rarely done in practice. +For each STAC Item, the Collection ID and Item ID must for a globally-unique tuple, e.g., item IDs are unique within a collection. + ## CORS Web browsers enforce a mechanism called [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) to prevent @@ -42,12 +48,12 @@ RFC 3339 is a profile of ISO 8601, adding these constraints to the allowed value A simple regex for an RFC 3339 datetime is: ```regex -^(\d\d\d\d)\-(\d\d)\-(\d\d)(T|t)(\d\d):(\d\d):(\d\d)([,.]\d+)?(Z|([-+])(\d\d):(\d\d))$ +^(\d\d\d\d)\-(\d\d)\-(\d\d)(T|t)(\d\d):(\d\d):(\d\d)([.]\d+)?(Z|([-+])(\d\d):(\d\d))$ ``` This is not a precise regex, as it matches some strings that violate semantics. There are additional restrictions, for example, the month (01-12), the day (01-31), the hour (0-24), minute (0-60), seconds (0-9), and timezone offsets. However, the best -strategy is to use this regex to ensure the datetime conforms to the the RFC3339 profile and then us an ISO8601 parser to produce +strategy is to use this regex to ensure the datetime conforms to the the RFC 3339 profile and then us an ISO8601 parser to produce a valid datetime object from the datetime string. Thereby, the recommended process for parsing the datetime value (which may consist of a single @@ -55,18 +61,19 @@ RFC 3339 datetime or an interval) is: 1. uppercase the string (this avoids needing to match on both (t|T) and (z|Z)) 2. split the string on `/` to determine if it is a single datetime or an interval -3. For the single value or each value of the split, check if it is either an open interval (the empty string or `..`), - or if it matches the RFC3339 datetime regex. Only one of the interval ends may be open. -4. ISO8601 parse datetime strings using a library such as [pyiso8601](https://github.com/micktwomey/pyiso8601) (Python), - [dateutil](https://dateutil.readthedocs.io/en/stable/parser.html#dateutil.parser.isoparse) (Python), or - [Luxon](https://github.com/moment/luxon/) (JavaScript). Frequently, date libraries built into language - standard libraries do not parse ISO8601 datetimes correctly, for example, the built-in Python datetime - library does not handle `Z` as a timezone. - -Below are a few examples of valid RFC 3339 datetimes. Note the uses of fractional seconds, the use of `.` or - `,` as the fractional seconds separator, Z or z as a timezone, -positive and negative arbitrary offset timezones, and T or t as a separator between date and time. While -the RFC3339 spec does not define the required number of fractional seconds, STAC API only requires up to +3. For the single value or each value of the split, check if it is either an open interval + (the empty string or `..`), or a datetime value. Only one of the interval ends may be open. +4. Either use an RFC 3339 datetime parser like in [ciso8601](https://github.com/closeio/ciso8601), or + match the datetime value against the RFC 3339 regex, upper case the string, and use an + ISO8601 parser such as [pyiso8601](https://github.com/micktwomey/pyiso8601) (Python) or + [Luxon](https://github.com/moment/luxon/) (JavaScript). Frequently, date libraries built into + language standard libraries do not parse ISO8601 datetimes correctly, for example, the built-in + Python datetime library does not handle `Z` as a timezone. + +Below are a few examples of valid RFC 3339 datetimes. Note the uses of fractional seconds, the use of `.` +as the fractional seconds separator, Z (recommended) or z as a timezone, +positive and negative arbitrary offset timezones, and T (recommended) or t as a separator between date and time. While +the RFC 3339 spec does not define the required number of fractional seconds, STAC API only requires up to 9 digits be supported. - 1990-12-31T23:59:59Z (no fractional seconds, Z timezone) diff --git a/item-search/README.md b/item-search/README.md index ba019598..8f29f7ac 100644 --- a/item-search/README.md +++ b/item-search/README.md @@ -2,6 +2,7 @@ - [STAC API - Item Search](#stac-api---item-search) - [Link Relations](#link-relations) + - [Endpoints](#endpoints) - [Query Parameters and Fields](#query-parameters-and-fields) - [Query Examples](#query-examples) - [Query Parameter Table](#query-parameter-table) @@ -20,8 +21,8 @@ - [Context](#context) - [Query](#query) -- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.3/item-search)) -- **Conformance URI:** +- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.4/item-search)) +- **Conformance URI:** - **Dependencies**: [STAC API - Core](../core) - **Examples**: [examples.md](examples.md) @@ -44,25 +45,25 @@ Implementing `GET /search` is **required**, `POST /search` is optional, but reco ## Link Relations -The following Link relations should exist in the Landing Page (root). +The following Link relations shall exist in the Landing Page (root). | **rel** | **href** | **From** | **Description** | | -------------- | -------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `root` | `/` | STAC Core | The root URI | | `self` | `/` | OAFeat | Self reference, same as root URI | -| `service-desc` | `/api` (recommended) | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API | +| `service-desc` | `/api` | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API. The path for this endpoint is only recommended to be `/api`, but may be another path. | | search | `/search` | STAC Item Search | URI for the Search endpoint | -Additionally, a `service-doc` endpoint is recommended. +A `service-doc` endpoint is recommended, but not required. | **rel** | **href** | **From** | **Description** | | ------------- | ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `service-doc` | `/api.html` (recommended) | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service | +| `service-doc` | `/api.html` | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service. The path for this endpoint is only recommended to be `/api.html`, but may be another path. | It is **required** to add a Link to the root endpoint (`/`) with the `rel` type set to `search` that refers to the search endpoint in the `href` property, with a `type` of `application/geo+json` and a `method` of `GET`. -This link should look like: +This link will look like: ```json { @@ -74,14 +75,22 @@ This link should look like: } ``` -Implementations that support `POST` should add a second link with the same structure but with a `method` of `POST`. +Implementations that support `POST` should add a second link with the same structure but with a `method` of `POST`. +## Endpoints + +| Endpoint | Returns | Description | +| -------- | ------- | ----------- | +| `/` | Catalog | Landing Page and root Catalog | +| `/api` | OAFeat OpenAPI | The OpenAPI service description. The path for this endpoint is only recommended to be `/api`, but may be another path. | +| `/search` | Item Collection | Search endpoint | + ## Query Parameters and Fields The following list of parameters is used to narrow search queries. They can all be represented as query string parameters in a GET request, or as JSON entity fields in a POST request. For filters that represent -a set of values, query parameters should use comma-separated string values with no enclosing brackets -(\[ or \]) and no whitespace between values, and JSON entity attributes should use JSON Arrays. +a set of values, query parameters must use comma-separated string values with no enclosing brackets +(\[ or \]) and no whitespace between values, and JSON entity attributes must use JSON Arrays. ### Query Examples @@ -115,8 +124,8 @@ The core parameters for STAC search are defined by OAFeat, and STAC adds a few p See [examples](examples.md) for some example requests. -Only one of either **intersects** or **bbox** should be specified. If both are specified, a 400 Bad Request response -should be returned. +Only one of either **intersects** or **bbox** may be specified. If both are specified, a 400 Bad Request response +must be returned. **datetime** The datetime parameter use the same allowed values as the [OAF datetime](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_parameter_datetime) parameter. @@ -135,7 +144,7 @@ elevation 0. ## Response -The response to a request (GET or POST) to the search endpoint should always be an +The response to a request (GET or POST) to the search endpoint must always be an [ItemCollection](../fragments/itemcollection/README.md) object - a valid [GeoJSON FeatureCollection](https://tools.ietf.org/html/rfc7946#section-3.3) that consists entirely of STAC [Item](../stac-spec/item-spec/item-spec.md) objects. @@ -168,7 +177,7 @@ The href may contain any arbitrary URL parameter: OAFeat does not support POST requests for searches, however the STAC API spec does. Hypermedia links are not designed for anything other than GET requests, so providing a next link for a POST search request becomes problematic. STAC has -decided to extend the `link` object to support additional fields that provide hints to the client as to how it should +decided to extend the `link` object to support additional fields that provide hints to the client as to how it must execute a subsequent request for the next page of results. The following fields have been added to the `link` object specification for the API spec: @@ -176,9 +185,9 @@ The following fields have been added to the `link` object specification for the | Parameter | Type | Description | | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | method | string | The HTTP method of the request, usually `GET` or `POST`. Defaults to `GET` | -| headers | object | A dictionary of header values that should be included in the next request | -| body | object | A JSON object containing fields/values that should be included in the body of the next request | -| merge | boolean | If `true`, the headers/body fields in the `next` link should be merged into the original request and be sent combined in the next request. Defaults to `false` | +| headers | object | A dictionary of header values that must be included in the next request | +| body | object | A JSON object containing fields/values that must be included in the body of the next request | +| merge | boolean | If `true`, the headers/body fields in the `next` link must be merged into the original request and be sent combined in the next request. Defaults to `false` | The implementor has the freedom to decide exactly how to apply these extended fields for their particular pagination mechanism. The same freedom that exists for GET requests, where the actual URL parameter used to defined the next page @@ -188,7 +197,7 @@ of their choosing. Pagination can be provided solely through header values, sole combination. To avoid returning the entire original request body in a POST response which may be arbitrarily large, the `merge` -property can be specified. This indicates that the client should send the same post body that it sent in the original +property can be specified. This indicates that the client must send the same post body that it sent in the original request, but with the specified headers/body values merged in. This allows servers to indicate what needs to change to get to the next page without mirroring the entire query structure back to the client. @@ -255,9 +264,10 @@ the [overview](../overview.md#example-landing-page) document. "id": "example-stac", "title": "A simple STAC API Example", "description": "This Catalog aims to demonstrate the a simple landing page", + "type": "Catalog", "conformsTo" : [ - "https://api.stacspec.org/v1.0.0-beta.3/core", - "https://api.stacspec.org/v1.0.0-beta.3/item-search" + "https://api.stacspec.org/v1.0.0-beta.4/core", + "https://api.stacspec.org/v1.0.0-beta.4/item-search" ], "links": [ { @@ -298,7 +308,7 @@ the root (`/`) landing page, to indicate to clients that they will respond prope ### Fields -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Fields Fragment](../fragments/fields/) @@ -310,7 +320,7 @@ through the use of a `fields` parameter. The full description of how this extens ### Filter -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Filter Fragment](../fragments/filter/) @@ -322,7 +332,7 @@ fragment](../fragments/filter/). ### Sort -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Sort Fragment](../fragments/sort/) @@ -335,7 +345,7 @@ of this extension can be found in the [sort fragment](../fragments/sort). ### Context -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Context Fragment](../fragments/context/) @@ -345,7 +355,7 @@ The full description and examples of this are found in the [context fragment](.. ### Query -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot, scheduled to be Deprecated - **Definition**: [STAC API - Query Fragment](../fragments/query/) diff --git a/item-search/openapi.yaml b/item-search/openapi.yaml index b719c42a..4f85b452 100644 --- a/item-search/openapi.yaml +++ b/item-search/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: STAC API - Item Search - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API - Item Search specification. diff --git a/ogcapi-features/README.md b/ogcapi-features/README.md index b4447ab1..9e5349df 100644 --- a/ogcapi-features/README.md +++ b/ogcapi-features/README.md @@ -9,13 +9,16 @@ - [Extensions](#extensions) - [Transaction](#transaction) - [Items and Collections API Version Extension](#items-and-collections-api-version-extension) + - [Fields](#fields) + - [Sort](#sort) + - [Context](#context) *based on [**OGC API - Features - Part 1: Core**](https://www.ogc.org/standards/ogcapi-features)* -- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.3/ogcapi-features)) +- **OpenAPI specification:** [openapi.yaml](openapi.yaml) ([rendered version](https://api.stacspec.org/v1.0.0-beta.4/ogcapi-features)) uses all the OGC API - Features openapi fragments to describe returning STAC Item objects. - **Conformance URIs:** - - + - - - [Requirements Class Core](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#rc_core)) - - [Requirements Class OpenAPI 3.0](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#rc_oas30)) - - [Requirements Class GeoJSON](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_requirements_class_geojson)) @@ -35,21 +38,21 @@ with OAFeat clients. But specialized STAC clients will likely display results be ## Link Relations -The following Link relations should exist in the Landing Page (root). +The following Link relations shall exist in the Landing Page (root). | **rel** | **href** | **From** | **Description** | | -------------- | -------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `root` | `/` | STAC Core | The root URI | | `self` | `/` | OAFeat | Self reference, same as root URI | | `conformance` | `/conformance` | OAFeat | Conformance URI | -| `service-desc` | `/api` (recommended) | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API | +| `service-desc` | `/api` | OAFeat OpenAPI | The OpenAPI service description. Uses the `application/vnd.oai.openapi+json;version=3.0` media type to refer to the OpenAPI 3.0 document that defines the service's API. The path for this endpoint is only recommended to be `/api`, but may be another path. | | `data` | `/collections` | OAFeat | List of Collections | -Additionally, a `service-doc` endpoint is recommended. +Additionally, a `service-doc` endpoint is recommended, but not required. | **rel** | **href** | **From** | **Description** | | ------------- | ------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `service-doc` | `/api.html` (recommended) | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service | +| `service-doc` | `/api.html` | OAFeat OpenAPI | An HTML service description. Uses the `text/html` media type to refer to a human-consumable description of the service. The path for this endpoint is only recommended to be `/api`, but may be another path. | ## Endpoints @@ -59,12 +62,12 @@ The core OGC API - Features endpoints are shown below, with details provided in | Endpoint | Returns | Description | | ----------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `/` | [Catalog](../stac-spec/catalog-spec/README.md) | Landing page, links to API capabilities | +| `/api` | OpenAPI 3.0 JSON | Returns an OpenAPI description of the service from the `service-desc` link `rel`. The path for this endpoint is only recommended to be `/api`, but may be another path. | | `/conformance` | JSON | Info about standards to which the API conforms | | `/collections` | JSON | Object containing an array of Collection objects in the Catalog, and Link relations | | `/collections/{collectionId}` | [Collection](../stac-spec/collection-spec/README.md) | Returns single Collection JSON | | `/collections/{collectionId}/items` | [ItemCollection](../fragments/itemcollection/README.md) | GeoJSON FeatureCollection-conformant entity of Item objects in collection | | `/collections/{collectionId}/items/{featureId}` | [Item](../stac-spec/item-spec/README.md) | Returns single Item (GeoJSON Feature) | -| `/api` | OpenAPI 3.0 JSON | Returns an OpenAPI description of the service from the `service-desc` link `rel` - not required to be `/api`, but the document is required | The OGC API - Features is a standard API that represents collections of geospatial data. It defines a RESTful interface to query geospatial data, with GeoJSON as a main return type. With OAFeat you can return any `Feature`, which is a geometry @@ -89,7 +92,7 @@ is outside the scope of STAC API, as the [STAC Item](../stac-spec/item-spec/item specified in GeoJSON. A typical OAFeat will have multiple collections. Simple search for items within a collection can be done -with the resource endpoint `GET /collections/{collectionId}/items`. This endpoint should be exposed via a +with the resource endpoint `GET /collections/{collectionId}/items`. This endpoint must be exposed via a link in the individual collection's endpoint with `rel=items`, as shown in the [Example Landing Page diagram](../overview.md#example-landing-page). Note that this relation is `items`, which is distinct from the `item` relation defined in STAC for linking to a single Item. The part of the API implementing OAFeat will usually not use @@ -150,9 +153,10 @@ the [overview](../overview.md#example-landing-page) document. "id": "example-stac", "title": "A simple STAC API Example", "description": "This Catalog aims to demonstrate the a simple landing page", + "type": "Catalog", "conformsTo" : [ - "https://api.stacspec.org/v1.0.0-beta.3/core", - "https://api.stacspec.org/v1.0.0-beta.3/ogcapi-features", + "https://api.stacspec.org/v1.0.0-beta.4/core", + "https://api.stacspec.org/v1.0.0-beta.4/ogcapi-features", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson" @@ -241,7 +245,7 @@ to requests from clients. ### Transaction - **Conformance URIs:** - - + - - - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Transaction Fragment](extensions/transaction/) @@ -253,10 +257,46 @@ POST, PUT, PATCH, and DELETE methods. The full description of how this extension ### Items and Collections API Version Extension -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot - **Definition**: [STAC API - Version](extensions/version/) The core API only supports semantics for creating and accessing a single version of an Item or Collection. The Version Extension defines the API resources and semantics for creating and accessing versioned records. It is the STAC API equivalent of [OGC API - Features - Part 4: Create, Replace, Update and Delete](https://docs.ogc.org/DRAFTS/20-002.html). + +### Fields + +- **Conformance URI:** +- **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot +- **Definition**: [STAC API - Fields Fragment](../fragments/fields/) + +By default, the Items resource `/collections/{collection_id}/items` returns all attributes +of each Item, as there is no way to specify +exactly those attributes that should be returned. The Fields extension to STAC Features adds new functionality that +allows the client to suggest to the server which Item attributes should be included or excluded in the response, +through the use of a `fields` parameter. The full description of how this extension works can be found in the +[fields fragment](../fragments/fields/). + +### Sort + +- **Conformance URI:** +- **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot +- **Definition**: [STAC API - Sort Fragment](../fragments/sort/) + +By default, the Items resource `/collections/{collection_id}/items` returns results in no specified order. Whatever order the results are in +is up to the implementor, and will typically default to an arbitrary order that is fastest for the underlying data store +to retrieve results. This extension adds a new parameter, `sortby`, that lets a user specify a comma separated list of +field names to sort by, with an indication of direction. It uses '+' and +'-' to indicate sort order of the list of fields. The full description of the semantics +of this extension can be found in the [sort fragment](../fragments/sort). + +### Context + +- **Conformance URI:** +- **Extension [Maturity Classification](../extensions.md#extension-maturity):** Pilot +- **Definition**: [STAC API - Context Fragment](../fragments/context/) + +This extension is intended to augment the core ItemCollection responses from the Items resource `/collections/{collection_id}/items` with a +JSON object called `context` that includes the number of items `matched`, `returned` and the `limit` requested. +The full description and examples of this are found in the [context fragment](../fragments/context). diff --git a/ogcapi-features/extensions/transaction/README.md b/ogcapi-features/extensions/transaction/README.md index 73d5b971..35629c5d 100644 --- a/ogcapi-features/extensions/transaction/README.md +++ b/ogcapi-features/extensions/transaction/README.md @@ -4,7 +4,7 @@ - **OpenAPI specification:** [openapi.yaml](openapi.yaml) - **Conformance URIs:** - - + - - - **Extension [Maturity Classification](../../../extensions.md#extension-maturity):** Pilot - **Dependencies**: [STAC API - Features](../../README.md) diff --git a/ogcapi-features/extensions/transaction/openapi.yaml b/ogcapi-features/extensions/transaction/openapi.yaml index a2bb850e..f98fb612 100644 --- a/ogcapi-features/extensions/transaction/openapi.yaml +++ b/ogcapi-features/extensions/transaction/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.1 info: title: The SpatioTemporal Asset Catalog API - Transaction - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API Transaction specification. diff --git a/ogcapi-features/extensions/version/README.md b/ogcapi-features/extensions/version/README.md index b6a4b7fd..aaf549fb 100644 --- a/ogcapi-features/extensions/version/README.md +++ b/ogcapi-features/extensions/version/README.md @@ -1,7 +1,7 @@ # Items and Collections API Version Extension - **OpenAPI specification:** [openapi.yaml](openapi.yaml) -- **Conformance URI:** +- **Conformance URI:** - **Extension [Maturity Classification](../../../extensions.md#extension-maturity):** Proposal - **Dependencies**: [STAC API - Features](../../README.md) @@ -37,8 +37,8 @@ list of links to all versions available for an item. ## Version ID -Version ID is a unique identifier for a version of an item or collection. -This extension remains agnostic about what the identifier should like. +Version ID is a unique identifier for a version of an Item or Collection. +This extension remains agnostic about what the identifier should be. There are many options for a versioning schema including: - md5 hash of the record - datetime epoch @@ -65,6 +65,7 @@ Request to `GET /collections/my_collection/items/this_is_my_id`: ```json { "id": "this_is_my_id", + "type": "Feature", "bbox": [], "geometry": {}, "properties": {}, @@ -97,6 +98,7 @@ Request to `GET /collections/my_collection/items/this_is_my_id/versions/02`: ```json { "id": "this_is_my_id", + "type": "Feature", "bbox": [], "geometry": {}, "properties": {}, @@ -129,6 +131,7 @@ Request to `GET /collections/my_collection/items/this_is_my_id/versions/01`: ```json { "id": "this_is_my_id", + "type": "Feature", "bbox": [], "geometry": {}, "properties": {}, diff --git a/ogcapi-features/extensions/version/openapi.yaml b/ogcapi-features/extensions/version/openapi.yaml index 6f720835..79a1e1f6 100644 --- a/ogcapi-features/extensions/version/openapi.yaml +++ b/ogcapi-features/extensions/version/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: The SpatioTemporal Asset Catalog API - Item Search - version: 1.0.0-beta.3 + version: 1.0.0-beta.4 description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API Item Search specification. diff --git a/ogcapi-features/openapi.yaml b/ogcapi-features/openapi.yaml index 70111cef..f4644e72 100644 --- a/ogcapi-features/openapi.yaml +++ b/ogcapi-features/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: STAC API - Features - version: '1.0.0-beta.3' + version: '1.0.0-beta.4' description: >- This is an OpenAPI definition of the SpatioTemporal Asset Catalog API - Features specification. This extends OGC API - Features - Part 1: Core. @@ -38,13 +38,13 @@ paths: schema: $ref: '../core/openapi.yaml#/components/schemas/landingPage' example: - stac_version: 1.0.0-beta.3 + stac_version: 1.0.0-beta.4 type: Catalog id: sentinel title: Copernicus Sentinel Imagery description: Catalog of Copernicus Sentinel 1 and 2 imagery. conformsTo: - - 'https://api.stacspec.org/v1.0.0-beta.3/core' + - 'https://api.stacspec.org/v1.0.0-beta.4/core' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30' - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson' diff --git a/overview.md b/overview.md index a8fdaecf..c1a892e5 100644 --- a/overview.md +++ b/overview.md @@ -20,7 +20,7 @@ off point for the more powerful capabilities - it contains a list of URL's, each 'relationships' (`rel`) to indicate their functionality. Note that the [STAC Core specification](stac-spec) provides most all the content of API responses - the STAC API is primarily concerned with the return of STAC [Item](stac-spec/item-spec/README.md) and [Collection](stac-spec/collection-spec/README.md) objects via a -RESTful web API. See the [rendered OpenAPI document](https://api.stacspec.org/v1.0.0-beta.3/core) for more details. +RESTful web API. See the [rendered OpenAPI document](https://api.stacspec.org/v1.0.0-beta.4/core) for more details. There are then two major sets of functionality that build on the core, which are designed to be complementary, letting implementations choose which parts they want to utilize. Most every STAC API implements at least one, and many follow @@ -33,7 +33,7 @@ located at a `/search` endpoint. It re-uses all of the OAFeat [query parameters](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_items_) specified in their 'core', and adds a couple more. It does not require a full implementation of OAFeat, it is instead a simplified construct that can run a search across any set of indexed STAC [`Item`](stac-spec/item-spec/README.md) objects. See the [rendered OpenAPI -document](https://api.stacspec.org/v1.0.0-beta.3/item-spec) for more details. +document](https://api.stacspec.org/v1.0.0-beta.4/item-spec) for more details. ### Collections @@ -65,7 +65,7 @@ is always in GeoJSON and OpenAPI is used to specify STAC API. Full compliance in individual `/collections/{collectionId}/items` endpoints that expose querying single collections, as OAFeat does not currently allow cross-collection search. And it adds a few other requirements, which are highlighted in the [features description](ogcapi-features/), in order to help STAC implementors understand OAFeat without having to -read the full spec from scratch. See the [rendered OpenAPI document](https://api.stacspec.org/v1.0.0-beta.3/ogcapi-features) +read the full spec from scratch. See the [rendered OpenAPI document](https://api.stacspec.org/v1.0.0-beta.4/ogcapi-features) for more details. ### Extensions & Fragments @@ -122,7 +122,7 @@ column is more of an example in some cases. OGC API makes some endpoint location STAC API is evolving to utilize OAFeat's '[Conformance](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_declaration_of_conformance_classes)' JSON structure. For -STAC API 1.0.0-beta.3 we declare new STAC Conformance classes, with the core ones detailed in the table below. [STAC +STAC API 1.0.0-beta.4 we declare new STAC Conformance classes, with the core ones detailed in the table below. [STAC Features](ogcapi-features) requires the core OAFeat conformance classes, and declares that those endpoints return STAC Collection and Feature objects. The core STAC conformance classes communicate the conformance JSON only in the root (`/`) document, while OGC API @@ -138,10 +138,10 @@ have the URI's for conformance to actually resolve to machine-readable informati | **Name** | **Specified in** | **Conformance URI** | **Description** | | ------------- | -------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| STAC Core | [Core](core) | | Specifies the STAC Landing page `/`, communicating conformance and available endpoints. | -| Item Search | [Item Search](item-search) | | Enables search of all STAC Item objects on the server, with the STAC `[/search](#stac-api-endpoints)` endpoint. | -| STAC Features | [STAC API - Features](ogcapi-features) | | Specifies the use of OGC API - Features to serve STAC Item and Collection objects | -| Collections | [Collections](collections) | | Specifies the use of a subset of OGC API - Features to serve Collection objects | +| STAC Core | [Core](core) | | Specifies the STAC Landing page `/`, communicating conformance and available endpoints. | +| Item Search | [Item Search](item-search) | | Enables search of all STAC Item objects on the server, with the STAC `[/search](#stac-api-endpoints)` endpoint. | +| STAC Features | [STAC API - Features](ogcapi-features) | | Specifies the use of OGC API - Features to serve STAC Item and Collection objects | +| Collections | [Collections](collections) | | Specifies the use of a subset of OGC API - Features to serve Collection objects | Additional conformance classes are specified in the [STAC Extensions](extensions.md#Conformance-classes-of-extensions). @@ -161,11 +161,12 @@ The Landing Page will at least have the following `conformsTo` and `links`: "id": "example-stac", "title": "A simple STAC API Example", "description": "This Catalog aims to demonstrate the a simple landing page", + "type": "Catalog", "conformsTo" : [ - "https://api.stacspec.org/v1.0.0-beta.3/core", - "https://api.stacspec.org/v1.0.0-beta.3/item-search", - "https://api.stacspec.org/v1.0.0-beta.3/ogcapi-features", - "https://api.stacspec.org/v1.0.0-beta.3/collections", + "https://api.stacspec.org/v1.0.0-beta.4/core", + "https://api.stacspec.org/v1.0.0-beta.4/item-search", + "https://api.stacspec.org/v1.0.0-beta.4/ogcapi-features", + "https://api.stacspec.org/v1.0.0-beta.4/collections", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/oas30", "http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson" diff --git a/package.json b/package.json index be5a0971..fc55b2fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "api-spec", - "version": "1.0.0-beta.3", + "version": "1.0.0-beta.4", "description": "STAC API helpers to generate, serve and check the API spec.", "repository": "https://github.com/radiantearth/stac-api-spec", "license": "Apache-2.0", @@ -31,4 +31,4 @@ "remark-preset-lint-recommended": "^4.0.1", "remark-validate-links": "^10.0.2" } -} +} \ No newline at end of file