You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@baremaps.apache.org by bc...@apache.org on 2023/04/26 07:21:27 UTC

[incubator-baremaps] 01/01: Add support for OGC-API feature

This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch 632-ogc-api-feature
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit 6f36a49571437a30b81f6ba4956a846919418387
Author: Bertil Chapuis <bc...@gmail.com>
AuthorDate: Wed Apr 26 09:21:10 2023 +0200

    Add support for OGC-API feature
---
 .../org/apache/baremaps/cli/ogcapi/OgcApi.java     |   3 +-
 .../baremaps/ogcapi/CollectionsResource.java       |  12 +
 .../org/apache/baremaps/ogcapi/ImportResource.java |  64 +--
 .../src/main/resources/ogcapi-openapi.yaml         | 461 +++++++++++++++++++++
 .../src/main/resources/parameters/bbox.yaml        |  48 +++
 .../main/resources/parameters/collectionId.yaml    |   6 +
 .../src/main/resources/parameters/datetime.yaml    |  23 +
 .../src/main/resources/parameters/featureId.yaml   |   6 +
 .../src/main/resources/parameters/limit.yaml       |  19 +
 .../schemas/featureCollectionGeoJSON.yaml          |  26 ++
 .../src/main/resources/schemas/featureGeoJSON.yaml |  22 +
 .../main/resources/schemas/geometryGeoJSON.yaml    |   8 +
 .../schemas/geometrycollectionGeoJSON.yaml         |  13 +
 .../main/resources/schemas/linestringGeoJSON.yaml  |  17 +
 .../resources/schemas/multilinestringGeoJSON.yaml  |  19 +
 .../main/resources/schemas/multipointGeoJSON.yaml  |  16 +
 .../resources/schemas/multipolygonGeoJSON.yaml     |  21 +
 .../src/main/resources/schemas/numberMatched.yaml  |   6 +
 .../src/main/resources/schemas/numberReturned.yaml |  11 +
 .../src/main/resources/schemas/pointGeoJSON.yaml   |  14 +
 .../src/main/resources/schemas/polygonGeoJSON.yaml |  19 +
 .../src/main/resources/schemas/timeStamp.yaml      |   4 +
 22 files changed, 808 insertions(+), 30 deletions(-)

diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/ogcapi/OgcApi.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/ogcapi/OgcApi.java
index b1a977fa..625e9ce9 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/ogcapi/OgcApi.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/ogcapi/OgcApi.java
@@ -67,7 +67,6 @@ public class OgcApi implements Callable<Integer> {
   public Integer call() throws Exception {
     // Configure serialization
     ObjectMapper mapper = defaultObjectMapper();
-    mapper.readValue("", JsonNode.class);
 
     // Configure jdbi and set the ObjectMapper
     DataSource datasource = PostgresUtils.dataSource(this.database);
@@ -81,7 +80,7 @@ public class OgcApi implements Callable<Integer> {
             ConformanceResource.class, CollectionsResource.class, StylesResource.class,
             TilesetsResource.class, StudioResource.class, ImportResource.class,
             MultiPartFeature.class)
-        .register(new ApiResource("studio-openapi.yaml")).register(contextResolverFor(mapper))
+        .register(new ApiResource("ogcapi-openapi.yaml")).register(contextResolverFor(mapper))
         .register(new AbstractBinder() {
           @Override
           protected void configure() {
diff --git a/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/CollectionsResource.java b/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/CollectionsResource.java
index ac11951d..4659cf35 100644
--- a/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/CollectionsResource.java
+++ b/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/CollectionsResource.java
@@ -14,6 +14,7 @@ package org.apache.baremaps.ogcapi;
 
 
 
+import java.math.BigDecimal;
 import java.net.URI;
 import java.util.List;
 import java.util.UUID;
@@ -91,4 +92,15 @@ public class CollectionsResource implements CollectionsApi {
         .bind("id", collectionId).bindByType("collection", collection, COLLECTION).execute());
     return Response.noContent().build();
   }
+
+  @Override
+  public Response getFeature(UUID collectionId, String featureId) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+  @Override
+  public Response getFeatures(UUID collectionId, Integer limit, List<BigDecimal> bbox,
+      String datetime) {
+    throw new UnsupportedOperationException("Not supported yet.");
+  }
 }
diff --git a/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/ImportResource.java b/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/ImportResource.java
index 18febaa4..30d27204 100644
--- a/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/ImportResource.java
+++ b/baremaps-ogcapi/src/main/java/org/apache/baremaps/ogcapi/ImportResource.java
@@ -42,34 +42,42 @@ public class ImportResource {
   @Path("studio/import")
   public Response uploadData(@FormDataParam("file") InputStream fileInputStream,
       @FormDataParam("file") FormDataContentDisposition fileMetaData) {
-    /*
-     * TODO: replace GeoTools with Apache SIS // Read FeatureCollection FeatureJSON fjson = new
-     * FeatureJSON(); var fc = fjson.readFeatureCollection(fileInputStream);
-     *
-     * // Setup Collection String fileName = fileMetaData.getFileName(); Collection collection = new
-     * Collection() .id(UUID.randomUUID()) .title(fileName.substring(0, fileName.lastIndexOf(".") -
-     * 1)) .extent( new Extent() .spatial( new ExtentSpatial() .bbox( List.of( List.of(
-     * fc.getBounds().getMinX(), fc.getBounds().getMinY(), fc.getBounds().getMaxX(),
-     * fc.getBounds().getMaxY()))))) .count(fc.size()) .created(new Date()) .geometryType(
-     * fc.getSchema().getGeometryDescriptor().getType().getBinding().getSimpleName());
-     *
-     * // Load data jdbi.useTransaction( handle -> { // Create collection handle .createUpdate(
-     * "insert into collections (id, collection) values (:id, CAST(:collection AS jsonb))")
-     * .bind("id", collection.getId()) .bindByType("collection", collection, COLLECTION) .execute();
-     * // Create table handle.execute( String.format(
-     * "create table \"%s\" (id serial, tags hstore, geom geometry)", collection.getId())); //
-     * Insert features var features = fc.features(); while (features.hasNext()) { SimpleFeature
-     * feature = (SimpleFeature) features.next(); HashMap<String, String> properties = new
-     * HashMap<>(); feature.getProperties().stream() .filter(property ->
-     * !property.getName().getLocalPart().equals("geometry")) .forEach( property -> properties.put(
-     * property.getName().getLocalPart(), property.getValue().toString())); Object geom =
-     * feature.getDefaultGeometryProperty().getValue(); handle .createUpdate( String.format(
-     * "insert into \"%s\" (tags, geom) values (:tags, ST_Transform(ST_SetSRID(CAST(:geom as geometry), 4326), 3857))"
-     * , collection.getId())) .bind("tags", properties) .bind("geom", geom.toString()) .execute(); }
-     * });
-     *
-     * return Response.created(URI.create("collections/" + collection.getId())).build();
-     */
+    // // Read FeatureCollection
+    // var fjson = new FeatureJSON();
+    // var fc = fjson.readFeatureCollection(fileInputStream);
+    //
+    // // Setup Collection
+    // String fileName = fileMetaData.getFileName();
+    // Collection collection = new Collection()
+    // .id(UUID.randomUUID())
+    // .title(fileName.substring(0, fileName.lastIndexOf(".") - 1))
+    // .extent(new Extent().spatial(new ExtentSpatial().bbox(List.of(List.of(
+    // fc.getBounds().getMinX(), fc.getBounds().getMinY(), fc.getBounds().getMaxX(),
+    // fc.getBounds().getMaxY()))))) .count(fc.size()) .created(new Date()) .geometryType(
+    // fc.getSchema().getGeometryDescriptor().getType().getBinding().getSimpleName());
+    //
+    // // Load data
+    // jdbi.useTransaction( handle -> {
+    // // Create collection
+    // handle .createUpdate(
+    // "insert into collections (id, collection) values (:id, CAST(:collection AS jsonb))")
+    // .bind("id", collection.getId()) .bindByType("collection", collection, COLLECTION) .execute();
+    // // Create table handle.execute( String.format(
+    // "create table \"%s\" (id serial, tags hstore, geom geometry)", collection.getId())); //
+    // // Insert features
+    // var features = fc.features(); while (features.hasNext()) {
+    // SimpleFeature feature = (SimpleFeature) features.next();
+    // HashMap<String, String> properties = new HashMap<>();
+    // feature.getProperties().stream()
+    // .filter(property -> !property.getName().getLocalPart().equals("geometry"))
+    // .forEach( property -> properties.put(property.getName().getLocalPart(),
+    // property.getValue().toString()));
+    // Object geom = feature.getDefaultGeometryProperty().getValue();
+    // handle.createUpdate( String.format("insert into \"%s\" (tags, geom) values (:tags,
+    // ST_Transform(ST_SetSRID(CAST(:geom as geometry), 4326), 3857))", collection.getId()))
+    // .bind("tags", properties) .bind("geom", geom.toString()) .execute(); }
+    // });
+    // return Response.created(URI.create("collections/" + collection.getId())).build();
     return Response.ok().build();
   }
 }
diff --git a/baremaps-ogcapi/src/main/resources/ogcapi-openapi.yaml b/baremaps-ogcapi/src/main/resources/ogcapi-openapi.yaml
index 14f590ca..fe56edde 100644
--- a/baremaps-ogcapi/src/main/resources/ogcapi-openapi.yaml
+++ b/baremaps-ogcapi/src/main/resources/ogcapi-openapi.yaml
@@ -244,6 +244,55 @@ paths:
         '404':
           description: |-
             collection not found
+  '/collections/{collectionId}/items':
+    get:
+      tags:
+        - Data
+      summary: fetch features
+      description: |-
+        Fetch features of the feature collection with id `collectionId`.
+        
+        Every feature in a dataset belongs to a collection. A dataset may
+        consist of multiple feature collections. A feature collection is often a
+        collection of features of a similar type, based on a common schema.
+        
+        Use content negotiation to request HTML or GeoJSON.
+      operationId: getFeatures
+      parameters:
+        - $ref: '#/components/parameters/collectionId'
+        - $ref: '#/components/parameters/limit'
+        - $ref: '#/components/parameters/bbox'
+        - $ref: '#/components/parameters/datetime'
+      responses:
+        '200':
+          $ref: '#/components/responses/Features'
+        '400':
+          $ref: '#/components/responses/InvalidParameter'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/ServerError'
+  '/collections/{collectionId}/items/{featureId}':
+    get:
+      tags:
+        - Data
+      summary: fetch a single feature
+      description: |-
+        Fetch the feature with id `featureId` in the feature collection
+        with id `collectionId`.
+
+        Use content negotiation to request HTML or GeoJSON.
+      operationId: getFeature
+      parameters:
+        - $ref: '#/components/parameters/collectionId'
+        - $ref: '#/components/parameters/featureId'
+      responses:
+        '200':
+          $ref: '#/components/responses/Feature'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/ServerError'
   /styles:
     summary: ddd
     description: xxx
@@ -575,6 +624,73 @@ paths:
                 $ref: 'schemas/exception.yaml'
 components:
   parameters:
+    bbox:
+      name: bbox
+      in: query
+      description: |-
+        Only features that have a geometry that intersects the bounding box are selected.
+        The bounding box is provided as four or six numbers, depending on whether the
+        coordinate reference system includes a vertical axis (height or depth):
+
+        * Lower left corner, coordinate axis 1
+        * Lower left corner, coordinate axis 2
+        * Minimum value, coordinate axis 3 (optional)
+        * Upper right corner, coordinate axis 1
+        * Upper right corner, coordinate axis 2
+        * Maximum value, coordinate axis 3 (optional)
+
+        If the value consists of four numbers, the coordinate reference system is
+        WGS 84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84)
+        unless a different coordinate reference system is specified in the parameter `bbox-crs`.
+
+        If the value consists of six numbers, the coordinate reference system is WGS 84 
+        longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h)
+        unless a different coordinate reference system is specified in the parameter `bbox-crs`.
+
+        The query parameter `bbox-crs` is specified in OGC API - Features - Part 2: Coordinate 
+        Reference Systems by Reference.
+
+        For WGS 84 longitude/latitude the values are in most cases the sequence of
+        minimum longitude, minimum latitude, maximum longitude and maximum latitude.
+        However, in cases where the box spans the antimeridian the first value
+        (west-most box edge) is larger than the third or fourth value (east-most box edge).
+
+        If the vertical axis is included, the third and the sixth number are
+        the bottom and the top of the 3-dimensional bounding box.
+
+        If a feature has multiple spatial geometry properties, it is the decision of the
+        server whether only a single spatial geometry property is used to determine
+        the extent or all relevant geometries.
+      required: false
+      schema:
+        type: array
+        oneOf:
+          - minItems: 4
+            maxItems: 4
+          - minItems: 6
+            maxItems: 6
+        items:
+          type: number
+      style: form
+      explode: false
+    datetime:
+      name: datetime
+      in: query
+      description: |-
+        Either a date-time or an interval. Date and time expressions adhere to RFC 3339. 
+        Intervals may be bounded or half-bounded (double-dots at start or end).
+
+        Only features that have a temporal property that intersects the value of
+        `datetime` are selected.
+
+        If a feature has multiple temporal properties, it is the decision of the
+        server whether only a single temporal property is used to determine
+        the extent or all relevant temporal properties.
+      required: false
+      schema:
+        type: string
+      style: form
+      explode: false
     collectionId:
       name: collectionId
       in: path
@@ -605,3 +721,348 @@ components:
       schema:
         type: string
         format: uuid
+    featureId:
+      name: featureId
+      in: path
+      description: local identifier of a feature
+      required: true
+      schema:
+        type: string
+    limit:
+      name: limit
+      in: query
+      description: |-
+        The optional limit parameter limits the number of items that are presented in the response document.
+        
+        Only items are counted that are on the first level of the collection in the response document.
+        Nested objects contained within the explicitly requested items shall not be counted.
+        
+        Minimum = 1. Maximum = 10000. Default = 10.
+      required: false
+      schema:
+        type: integer
+        minimum: 1
+        maximum: 10000
+        default: 10
+      style: form
+      explode: false
+  responses:
+    LandingPage:
+      description: |-
+        The landing page provides links to the API definition
+        (link relations `service-desc` and `service-doc`),
+        the Conformance declaration (path `/conformance`,
+        link relation `conformance`), and the Feature
+        Collections (path `/collections`, link relation
+        `data`).
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/landingPage'
+          example:
+            title: Buildings in Bonn
+            description: Access to data about buildings in the city of Bonn via a Web API that conforms to the OGC API Features specification.
+            links:
+              - href: 'http://data.example.org/'
+                rel: self
+                type: application/json
+                title: this document
+              - href: 'http://data.example.org/api'
+                rel: service-desc
+                type: application/vnd.oai.openapi+json;version=3.0
+                title: the API definition
+              - href: 'http://data.example.org/api.html'
+                rel: service-doc
+                type: text/html
+                title: the API documentation
+              - href: 'http://data.example.org/conformance'
+                rel: conformance
+                type: application/json
+                title: OGC API conformance classes implemented by this server
+              - href: 'http://data.example.org/collections'
+                rel: data
+                type: application/json
+                title: Information about the feature collections
+        text/html:
+          schema:
+            type: string
+    ConformanceDeclaration:
+      description: |-
+        The URIs of all conformance classes supported by the server.
+
+        To support "generic" clients that want to access multiple
+        OGC API Features implementations - and not "just" a specific
+        API / server, the server declares the conformance
+        classes it implements and conforms to.
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/confClasses'
+          example:
+            conformsTo:
+              - '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/html'
+              - 'http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/geojson'
+        text/html:
+          schema:
+            type: string
+    Collections:
+      description: |-
+        The feature collections shared by this API.
+
+        The dataset is organized as one or more feature collections. This resource
+        provides information about and access to the collections.
+
+        The response contains the list of collections. For each collection, a link
+        to the items in the collection (path `/collections/{collectionId}/items`,
+        link relation `items`) as well as key information about the collection.
+        This information includes:
+
+        * A local identifier for the collection that is unique for the dataset;
+        * An optional list of coordinate reference systems (CRS) in which geometries may be returned by the server. The default value is a list with the default CRS (WGS 84 with axis order longitude/latitude).
+        * An optional title and description for the collection;
+        * An optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data;
+        * An optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature').
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/collections'
+          example:
+            links:
+              - href: 'http://data.example.org/collections.json'
+                rel: self
+                type: application/json
+                title: this document
+              - href: 'http://data.example.org/collections.html'
+                rel: alternate
+                type: text/html
+                title: this document as HTML
+              - href: 'http://schemas.example.org/1.0/buildings.xsd'
+                rel: describedby
+                type: application/xml
+                title: GML application schema for Acme Corporation building data
+              - href: 'http://download.example.org/buildings.gpkg'
+                rel: enclosure
+                type: application/geopackage+sqlite3
+                title: Bulk download (GeoPackage)
+                length: 472546
+            collections:
+              - id: buildings
+                title: Buildings
+                description: Buildings in the city of Bonn.
+                extent:
+                  spatial:
+                    bbox:
+                      - - 7.01
+                        - 50.63
+                        - 7.22
+                        - 50.78
+                  temporal:
+                    interval:
+                      - - '2010-02-15T12:34:56Z'
+                        - null
+                links:
+                  - href: 'http://data.example.org/collections/buildings/items'
+                    rel: items
+                    type: application/geo+json
+                    title: Buildings
+                  - href: 'http://data.example.org/collections/buildings/items.html'
+                    rel: items
+                    type: text/html
+                    title: Buildings
+                  - href: 'https://creativecommons.org/publicdomain/zero/1.0/'
+                    rel: license
+                    type: text/html
+                    title: CC0-1.0
+                  - href: 'https://creativecommons.org/publicdomain/zero/1.0/rdf'
+                    rel: license
+                    type: application/rdf+xml
+                    title: CC0-1.0
+        text/html:
+          schema:
+            type: string
+    Collection:
+      description: |-
+        Information about the feature collection with id `collectionId`.
+
+        The response contains a link to the items in the collection
+        (path `/collections/{collectionId}/items`, link relation `items`)
+        as well as key information about the collection. This information
+        includes:
+
+        * A local identifier for the collection that is unique for the dataset;
+        * An optional list of coordinate reference systems (CRS) in which geometries may be returned by the server. The default value is a list with the default CRS (WGS 84 with axis order longitude/latitude).
+        * An optional title and description for the collection;
+        * An optional extent that can be used to provide an indication of the spatial and temporal extent of the collection - typically derived from the data;
+        * An optional indicator about the type of the items in the collection (the default value, if the indicator is not provided, is 'feature').
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/collection'
+          example:
+            id: buildings
+            title: Buildings
+            description: Buildings in the city of Bonn.
+            extent:
+              spatial:
+                bbox:
+                  - - 7.01
+                    - 50.63
+                    - 7.22
+                    - 50.78
+              temporal:
+                interval:
+                  - - '2010-02-15T12:34:56Z'
+                    - null
+            links:
+              - href: 'http://data.example.org/collections/buildings/items'
+                rel: items
+                type: application/geo+json
+                title: Buildings
+              - href: 'http://data.example.org/collections/buildings/items.html'
+                rel: items
+                type: text/html
+                title: Buildings
+              - href: 'https://creativecommons.org/publicdomain/zero/1.0/'
+                rel: license
+                type: text/html
+                title: CC0-1.0
+              - href: 'https://creativecommons.org/publicdomain/zero/1.0/rdf'
+                rel: license
+                type: application/rdf+xml
+                title: CC0-1.0
+        text/html:
+          schema:
+            type: string
+    Features:
+      description: |-
+        The response is a document consisting of features in the collection.
+        The features included in the response are determined by the server
+        based on the query parameters of the request. To support access to
+        larger collections without overloading the client, the API supports
+        paged access with links to the next page, if more features are selected
+        that the page size.
+
+        The `bbox` and `datetime` parameter can be used to select only a
+        subset of the features in the collection (the features that are in the
+        bounding box or time interval). The `bbox` parameter matches all features
+        in the collection that are not associated with a location, too. The
+        `datetime` parameter matches all features in the collection that are
+        not associated with a time stamp or interval, too.
+
+        The `limit` parameter may be used to control the subset of the
+        selected features that should be returned in the response, the page size.
+        Each page may include information about the number of selected and
+        returned features (`numberMatched` and `numberReturned`) as well as
+        links to support paging (link relation `next`).
+      content:
+        application/geo+json:
+          schema:
+            $ref: 'schemas/featureCollectionGeoJSON.yaml'
+          example:
+            type: FeatureCollection
+            links:
+              - href: 'http://data.example.com/collections/buildings/items.json'
+                rel: self
+                type: application/geo+json
+                title: this document
+              - href: 'http://data.example.com/collections/buildings/items.html'
+                rel: alternate
+                type: text/html
+                title: this document as HTML
+              - href: 'http://data.example.com/collections/buildings/items.json&offset=10&limit=2'
+                rel: next
+                type: application/geo+json
+                title: next page
+            timeStamp: '2018-04-03T14:52:23Z'
+            numberMatched: 123
+            numberReturned: 2
+            features:
+              - type: Feature
+                id: '123'
+                geometry:
+                  type: Polygon
+                  coordinates:
+                    - ...
+                properties:
+                  function: residential
+                  floors: '2'
+                  lastUpdate: '2015-08-01T12:34:56Z'
+              - type: Feature
+                id: '132'
+                geometry:
+                  type: Polygon
+                  coordinates:
+                    - ...
+                properties:
+                  function: public use
+                  floors: '10'
+                  lastUpdate: '2013-12-03T10:15:37Z'
+        text/html:
+          schema:
+            type: string
+    Feature:
+      description: |-
+        fetch the feature with id `featureId` in the feature collection
+        with id `collectionId`
+      content:
+        application/geo+json:
+          schema:
+            $ref: 'schemas/featureGeoJSON.yaml'
+          example:
+            type: Feature
+            links:
+              - href: 'http://data.example.com/id/building/123'
+                rel: canonical
+                title: canonical URI of the building
+              - href: 'http://data.example.com/collections/buildings/items/123.json'
+                rel: self
+                type: application/geo+json
+                title: this document
+              - href: 'http://data.example.com/collections/buildings/items/123.html'
+                rel: alternate
+                type: text/html
+                title: this document as HTML
+              - href: 'http://data.example.com/collections/buildings'
+                rel: collection
+                type: application/geo+json
+                title: the collection document
+            id: '123'
+            geometry:
+              type: Polygon
+              coordinates:
+                - ...
+            properties:
+              function: residential
+              floors: '2'
+              lastUpdate: '2015-08-01T12:34:56Z'
+        text/html:
+          schema:
+            type: string
+    InvalidParameter:
+      description: |-
+        A query parameter has an invalid value.
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/exception'
+        text/html:
+          schema:
+            type: string
+    NotFound:
+      description: |-
+        The requested resource does not exist on the server. For example, a path parameter had an incorrect value.
+    NotAcceptable:
+      description: |-
+        Content negotiation failed. For example, the `Accept` header submitted in the request did not support any of the media types supported by the server for the requested resource.
+    ServerError:
+      description: |-
+        A server error occurred.
+      content:
+        application/json:
+          schema:
+            $ref: '#/components/schemas/exception'
+        text/html:
+          schema:
+            type: string
diff --git a/baremaps-ogcapi/src/main/resources/parameters/bbox.yaml b/baremaps-ogcapi/src/main/resources/parameters/bbox.yaml
new file mode 100644
index 00000000..d44ea8dc
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/parameters/bbox.yaml
@@ -0,0 +1,48 @@
+name: bbox
+in: query
+description: |-
+  Only features that have a geometry that intersects the bounding box are selected.
+  The bounding box is provided as four or six numbers, depending on whether the
+  coordinate reference system includes a vertical axis (height or depth):
+
+  * Lower left corner, coordinate axis 1
+  * Lower left corner, coordinate axis 2
+  * Minimum value, coordinate axis 3 (optional)
+  * Upper right corner, coordinate axis 1
+  * Upper right corner, coordinate axis 2
+  * Maximum value, coordinate axis 3 (optional)
+
+  If the value consists of four numbers, the coordinate reference system is
+  WGS 84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84)
+  unless a different coordinate reference system is specified in the parameter `bbox-crs`.
+
+  If the value consists of six numbers, the coordinate reference system is WGS 84 
+  longitude/latitude/ellipsoidal height (http://www.opengis.net/def/crs/OGC/0/CRS84h)
+  unless a different coordinate reference system is specified in the parameter `bbox-crs`.
+
+  The query parameter `bbox-crs` is specified in OGC API - Features - Part 2: Coordinate 
+  Reference Systems by Reference.
+
+  For WGS 84 longitude/latitude the values are in most cases the sequence of
+  minimum longitude, minimum latitude, maximum longitude and maximum latitude.
+  However, in cases where the box spans the antimeridian the first value
+  (west-most box edge) is larger than the third or fourth value (east-most box edge).
+
+  If the vertical axis is included, the third and the sixth number are the
+  bottom and the top of the 3-dimensional bounding box.
+
+  If a feature has multiple spatial geometry properties, it is the decision of the
+  server whether only a single spatial geometry property is used to determine
+  the extent or all relevant geometries.
+required: false
+schema:
+  type: array
+  oneOf:
+  - minItems: 4
+    maxItems: 4
+  - minItems: 6
+    maxItems: 6
+  items:
+    type: number
+style: form
+explode: false
diff --git a/baremaps-ogcapi/src/main/resources/parameters/collectionId.yaml b/baremaps-ogcapi/src/main/resources/parameters/collectionId.yaml
new file mode 100644
index 00000000..5ad15f20
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/parameters/collectionId.yaml
@@ -0,0 +1,6 @@
+name: collectionId
+in: path
+description: local identifier of a collection
+required: true
+schema:
+  type: string
diff --git a/baremaps-ogcapi/src/main/resources/parameters/datetime.yaml b/baremaps-ogcapi/src/main/resources/parameters/datetime.yaml
new file mode 100644
index 00000000..c2fd5003
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/parameters/datetime.yaml
@@ -0,0 +1,23 @@
+name: datetime
+in: query
+description: |-
+  Either a date-time or an interval. Date and time expressions adhere to RFC 3339. 
+  Intervals may be bounded or half-bounded (double-dots at start or end).
+
+  Examples:
+
+  * A date-time: "2018-02-12T23:20:50Z"
+  * A bounded interval: "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z"
+  * Half-bounded intervals: "2018-02-12T00:00:00Z/.." or "../2018-03-18T12:31:12Z"
+
+  Only features that have a temporal property that intersects the value of
+  `datetime` are selected.
+
+  If a feature has multiple temporal properties, it is the decision of the
+  server whether only a single temporal property is used to determine
+  the extent or all relevant temporal properties.
+required: false
+schema:
+  type: string
+style: form
+explode: false
diff --git a/baremaps-ogcapi/src/main/resources/parameters/featureId.yaml b/baremaps-ogcapi/src/main/resources/parameters/featureId.yaml
new file mode 100644
index 00000000..0e9c1982
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/parameters/featureId.yaml
@@ -0,0 +1,6 @@
+name: featureId
+in: path
+description: local identifier of a feature
+required: true
+schema:
+  type: string
diff --git a/baremaps-ogcapi/src/main/resources/parameters/limit.yaml b/baremaps-ogcapi/src/main/resources/parameters/limit.yaml
new file mode 100644
index 00000000..f98f8a4f
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/parameters/limit.yaml
@@ -0,0 +1,19 @@
+name: limit
+in: query
+description: |-
+  The optional limit parameter limits the number of items that are presented in the response document.
+
+  Only items are counted that are on the first level of the collection in the response document.
+  Nested objects contained within the explicitly requested items shall not be counted.
+
+  Minimum = 1. Maximum = 10000. Default = 100.
+
+  Note that the values for minimum, maximum and default are examples and can be changed.
+required: false
+schema:
+  type: integer
+  minimum: 1
+  maximum: 10000
+  default: 100
+style: form
+explode: false
diff --git a/baremaps-ogcapi/src/main/resources/schemas/featureCollectionGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/featureCollectionGeoJSON.yaml
new file mode 100644
index 00000000..2caf5dae
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/featureCollectionGeoJSON.yaml
@@ -0,0 +1,26 @@
+type: object
+required:
+  - type
+  - features
+properties:
+  type:
+    type: string
+    enum:
+      - FeatureCollection
+  features:
+    type: array
+    items:
+      $ref: featureGeoJSON.yaml
+  links:
+    type: array
+    items:
+      $ref: link.yaml
+  timeStamp:
+    type: string
+    format: date-time
+  numberMatched:
+    type: integer
+    minimum: 0
+  numberReturned:
+    type: integer
+    minimum: 0
diff --git a/baremaps-ogcapi/src/main/resources/schemas/featureGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/featureGeoJSON.yaml
new file mode 100644
index 00000000..008bb421
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/featureGeoJSON.yaml
@@ -0,0 +1,22 @@
+type: object
+required:
+  - type
+  - geometry
+  - properties
+properties:
+  type:
+    type: string
+    enum:
+      - Feature
+  geometry:
+    $ref: 'geometryGeoJSON.yaml'
+  properties:
+    type: object
+    nullable: true
+  id:
+    type: string
+  links:
+    type: array
+    items:
+      $ref: link.yaml
+      
diff --git a/baremaps-ogcapi/src/main/resources/schemas/geometryGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/geometryGeoJSON.yaml
new file mode 100644
index 00000000..28ef965e
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/geometryGeoJSON.yaml
@@ -0,0 +1,8 @@
+oneOf:
+- $ref: 'pointGeoJSON.yaml'
+- $ref: 'multipointGeoJSON.yaml'
+- $ref: 'linestringGeoJSON.yaml'
+- $ref: 'multilinestringGeoJSON.yaml'
+- $ref: 'polygonGeoJSON.yaml'
+- $ref: 'multipolygonGeoJSON.yaml'
+- $ref: 'geometrycollectionGeoJSON.yaml'
diff --git a/baremaps-ogcapi/src/main/resources/schemas/geometrycollectionGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/geometrycollectionGeoJSON.yaml
new file mode 100644
index 00000000..91f3127e
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/geometrycollectionGeoJSON.yaml
@@ -0,0 +1,13 @@
+type: object
+required:
+  - type
+  - geometries
+properties:
+  type:
+    type: string
+    enum:
+      - GeometryCollection
+  geometries:
+    type: array
+    items:
+      $ref: 'geometryGeoJSON.yaml'
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/linestringGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/linestringGeoJSON.yaml
new file mode 100644
index 00000000..50f6338d
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/linestringGeoJSON.yaml
@@ -0,0 +1,17 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - LineString
+  coordinates:
+    type: array
+    minItems: 2
+    items:
+      type: array
+      minItems: 2
+      items:
+        type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/multilinestringGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/multilinestringGeoJSON.yaml
new file mode 100644
index 00000000..3a7edca7
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/multilinestringGeoJSON.yaml
@@ -0,0 +1,19 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - MultiLineString
+  coordinates:
+    type: array
+    items:
+      type: array
+      minItems: 2
+      items:
+        type: array
+        minItems: 2
+        items:
+          type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/multipointGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/multipointGeoJSON.yaml
new file mode 100644
index 00000000..b100f5f4
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/multipointGeoJSON.yaml
@@ -0,0 +1,16 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - MultiPoint
+  coordinates:
+    type: array
+    items:
+      type: array
+      minItems: 2
+      items:
+        type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/multipolygonGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/multipolygonGeoJSON.yaml
new file mode 100644
index 00000000..0a4a27c8
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/multipolygonGeoJSON.yaml
@@ -0,0 +1,21 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - MultiPolygon
+  coordinates:
+    type: array
+    items:
+      type: array
+      items:
+        type: array
+        minItems: 4
+        items:
+          type: array
+          minItems: 2
+          items:
+            type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/numberMatched.yaml b/baremaps-ogcapi/src/main/resources/schemas/numberMatched.yaml
new file mode 100644
index 00000000..feb63abf
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/numberMatched.yaml
@@ -0,0 +1,6 @@
+description: |-
+  The number of features of the feature type that match the selection
+  parameters like `bbox`.
+type: integer
+minimum: 0
+example: 127
diff --git a/baremaps-ogcapi/src/main/resources/schemas/numberReturned.yaml b/baremaps-ogcapi/src/main/resources/schemas/numberReturned.yaml
new file mode 100644
index 00000000..d4da41d6
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/numberReturned.yaml
@@ -0,0 +1,11 @@
+description: |-
+  The number of features in the feature collection.
+
+  A server may omit this information in a response, if the information
+  about the number of features is not known or difficult to compute.
+
+  If the value is provided, the value shall be identical to the number
+  of items in the "features" array.
+type: integer
+minimum: 0
+example: 10
diff --git a/baremaps-ogcapi/src/main/resources/schemas/pointGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/pointGeoJSON.yaml
new file mode 100644
index 00000000..f4656661
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/pointGeoJSON.yaml
@@ -0,0 +1,14 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - Point
+  coordinates:
+    type: array
+    minItems: 2
+    items:
+      type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/polygonGeoJSON.yaml b/baremaps-ogcapi/src/main/resources/schemas/polygonGeoJSON.yaml
new file mode 100644
index 00000000..298bcc91
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/polygonGeoJSON.yaml
@@ -0,0 +1,19 @@
+type: object
+required:
+  - type
+  - coordinates
+properties:
+  type:
+    type: string
+    enum:
+      - Polygon
+  coordinates:
+    type: array
+    items:
+      type: array
+      minItems: 4
+      items:
+        type: array
+        minItems: 2
+        items:
+          type: number
\ No newline at end of file
diff --git a/baremaps-ogcapi/src/main/resources/schemas/timeStamp.yaml b/baremaps-ogcapi/src/main/resources/schemas/timeStamp.yaml
new file mode 100644
index 00000000..3a7eb8ec
--- /dev/null
+++ b/baremaps-ogcapi/src/main/resources/schemas/timeStamp.yaml
@@ -0,0 +1,4 @@
+description: This property indicates the time and date when the response was generated.
+type: string
+format: date-time
+example: '2017-08-17T08:05:32Z'