[Git][debian-gis-team/pygeoapi][master] 4 commits: Update copyright

Angelos Tzotsos (@kalxas-guest) gitlab at salsa.debian.org
Fri Apr 5 13:56:46 BST 2024



Angelos Tzotsos pushed to branch master at Debian GIS Project / pygeoapi


Commits:
7689e2ce by Angelos Tzotsos at 2024-04-05T15:50:59+03:00
Update copyright

- - - - -
4f2e4bb8 by Angelos Tzotsos at 2024-04-05T15:51:05+03:00
New upstream version 0.16.1
- - - - -
33568159 by Angelos Tzotsos at 2024-04-05T15:51:42+03:00
Update upstream source from tag 'upstream/0.16.1'

Update to upstream version '0.16.1'
with Debian dir f4b08bed8257e88f7b7d4d42bd09676523873221
- - - - -
87acffe3 by Angelos Tzotsos at 2024-04-05T15:55:28+03:00
New upstream release 0.16.1

- - - - -


8 changed files:

- debian/changelog
- debian/copyright
- docs/source/administration.rst
- docs/source/conf.py
- docs/source/openapi.rst
- pygeoapi/__init__.py
- pygeoapi/flask_app.py
- pygeoapi/openapi.py


Changes:

=====================================
debian/changelog
=====================================
@@ -1,4 +1,4 @@
-pygeoapi (0.16.0-1) UNRELEASED; urgency=medium
+pygeoapi (0.16.1-1) UNRELEASED; urgency=medium
 
   [ Felix Delattre ]
   * New upstream release 0.15.0
@@ -13,5 +13,6 @@ pygeoapi (0.16.0-1) UNRELEASED; urgency=medium
 
   [ Angelos Tzotsos ]
   * New upstream release 0.16.0
+  * New upstream release 0.16.1
 
  -- Angelos Tzotsos <gcpp.kalxas at gmail.com>  Mon, 11 Mar 2024 16:33:43 +0200


=====================================
debian/copyright
=====================================
@@ -4,11 +4,11 @@ Upstream-Contact: Tom Kralidis <tomkralidis at gmail.com>
 Source: https://github.com/geopython/pygeoapi
 
 Files: *
-Copyright: 2018-2023, Tom Kralidis <tomkralidis at gmail.com>
+Copyright: 2018-2024, Tom Kralidis <tomkralidis at gmail.com>
 License: MIT
 
 Files: debian/*
-Copyright: 2021-2023, Angelos Tzotsos <gcpp.kalxas at gmail.com>
+Copyright: 2021-2024, Angelos Tzotsos <gcpp.kalxas at gmail.com>
                 2023, Felix Delattre <debian at xama.nu>
 License: GPL-2+
 


=====================================
docs/source/administration.rst
=====================================
@@ -49,6 +49,10 @@ To generate the OpenAPI document as JSON, run:
    property names and their data types.  Whenever you make changes to your pygeoapi configuration,
    always refresh the accompanying OpenAPI document.
 
+.. note::
+   By default, pygeoapi OpenAPI document generation will fail on any collection whose provider is improperly
+   configured or when encountering a connection issue.  To skip failing collections, use the
+   --no-fail-on-invalid-collection flag.  The OpenAPI document will then be generated without the failing collection(s)
 
 .. seealso::
    :ref:`openapi` for more information on pygeoapi's OpenAPI support


=====================================
docs/source/conf.py
=====================================
@@ -112,7 +112,7 @@ today_fmt = '%Y-%m-%d'
 # built documents.
 #
 # The short X.Y version.
-version = '0.16.0'
+version = '0.16.1'
 # The full version, including alpha/beta/rc tags.
 release = version
 


=====================================
docs/source/openapi.rst
=====================================
@@ -13,7 +13,7 @@ The official OpenAPI specification can be found `on GitHub <https://github.com/O
 pygeoapi supports OpenAPI version 3.0.2.
 
 As described in :ref:`administration`, the pygeoapi OpenAPI document is automatically generated based on the
-configuration file:
+configuration file.
 
 The API is accessible at the ``/openapi`` endpoint, providing a Swagger-based webpage of the API description..
 


=====================================
pygeoapi/__init__.py
=====================================
@@ -30,7 +30,7 @@
 #
 # =================================================================
 
-__version__ = '0.16.0'
+__version__ = '0.16.1'
 
 import click
 try:


=====================================
pygeoapi/flask_app.py
=====================================
@@ -101,8 +101,11 @@ if (OGC_SCHEMAS_LOCATION is not None and
         dirname_ = os.path.dirname(full_filepath)
         basename_ = os.path.basename(full_filepath)
 
-        # TODO: better sanitization?
-        path_ = dirname_.replace('..', '').replace('//', '')
+        path_ = dirname_.replace('..', '').replace('//', '').replace('./', '')
+
+        if '..' in path_:
+            return 'Invalid path', 400
+
         return send_from_directory(path_, basename_,
                                    mimetype=get_mimetype(basename_))
 


=====================================
pygeoapi/openapi.py
=====================================
@@ -37,7 +37,7 @@ import json
 import logging
 import os
 from pathlib import Path
-from typing import Union
+from typing import Tuple, Union
 
 import click
 from jsonschema import validate as jsonschema_validate
@@ -68,7 +68,14 @@ OPENAPI_YAML = {
 THISDIR = os.path.dirname(os.path.realpath(__file__))
 
 
-def get_ogc_schemas_location(server_config):
+def get_ogc_schemas_location(server_config: dict) -> str:
+    """
+    Determine OGC schemas location
+
+    :param server_config: `dict` of server configuration
+
+    :returns: `str` of OGC schemas location
+    """
 
     osl = server_config.get('ogc_schemas_location')
 
@@ -85,7 +92,7 @@ def get_ogc_schemas_location(server_config):
 
 
 # TODO: remove this function once OGC API - Processing is final
-def gen_media_type_object(media_type, api_type, path):
+def gen_media_type_object(media_type: str, api_type: str, path: str) -> dict:
     """
     Generates an OpenAPI Media Type Object
 
@@ -110,7 +117,8 @@ def gen_media_type_object(media_type, api_type, path):
 
 
 # TODO: remove this function once OGC API - Processing is final
-def gen_response_object(description, media_type, api_type, path):
+def gen_response_object(description: str, media_type: str,
+                        api_type: str, path: str) -> dict:
     """
     Generates an OpenAPI Response Object
 
@@ -129,13 +137,15 @@ def gen_response_object(description, media_type, api_type, path):
     return response
 
 
-def get_oas_30(cfg):
+def get_oas_30(cfg: dict, fail_on_invalid_collection: bool = True) -> dict:
     """
     Generates an OpenAPI 3.0 Document
 
     :param cfg: configuration object
+    :param fail_on_invalid_collection: `bool` of whether to fail on an invalid
+                                       collection
 
-    :returns: OpenAPI definition YAML dict
+    :returns: dict of OpenAPI definition
     """
 
     paths = {}
@@ -297,6 +307,16 @@ def get_oas_30(cfg):
                         'schema': {'$ref': '#/components/schemas/queryables'}
                     }
                 }
+            },
+            'Tiles': {
+                'description': 'Retrieves the tiles description for this collection', # noqa
+                'content': {
+                    'application/json': {
+                        'schema': {
+                            '$ref': '#/components/schemas/tiles'
+                        }
+                    }
+                }
             }
         },
         'parameters': {
@@ -492,1084 +512,1115 @@ def get_oas_30(cfg):
                         'items': {'$ref': '#/components/schemas/queryable'}
                     }
                 }
+            },
+            'tilematrixsetlink': {
+                'type': 'object',
+                'required': ['tileMatrixSet'],
+                'properties': {
+                    'tileMatrixSet': {
+                        'type': 'string'
+                    },
+                    'tileMatrixSetURI': {
+                        'type': 'string'
+                    }
+                }
+            },
+            'tiles': {
+                'type': 'object',
+                'required': [
+                    'tileMatrixSetLinks',
+                    'links'
+                ],
+                'properties': {
+                    'tileMatrixSetLinks': {
+                        'type': 'array',
+                        'items': {
+                            '$ref': '#/components/schemas/tilematrixsetlink' # noqa
+                        }
+                    },
+                    'links': {
+                        'type': 'array',
+                        'items': {'$ref': f"{OPENAPI_YAML['oapit']}#/components/schemas/link"}  # noqa
+                    }
+                }
             }
         }
     }
 
-    items_f = deepcopy(oas['components']['parameters']['f'])
-    items_f['schema']['enum'].append('csv')
-    items_l = deepcopy(oas['components']['parameters']['lang'])
-
     LOGGER.debug('setting up datasets')
     collections = filter_dict_by_key_value(cfg['resources'],
                                            'type', 'collection')
 
     for k, v in collections.items():
-        if v.get('visibility', 'default') == 'hidden':
-            LOGGER.debug(f'Skipping hidden layer: {k}')
-            continue
-        name = l10n.translate(k, locale_)
-        title = l10n.translate(v['title'], locale_)
-        desc = l10n.translate(v['description'], locale_)
-        collection_name_path = f'/collections/{k}'
-        tag = {
-            'name': name,
-            'description': desc,
-            'externalDocs': {}
+        try:
+            LOGGER.debug(f'Generating OpenAPI tags/paths for collection {k}')
+            r_tags, r_paths = handle_collection(locale_, oas['components'],
+                                                k, v)
+            oas['tags'].extend(r_tags)
+            paths.update(r_paths)
+        except Exception as err:
+            if fail_on_invalid_collection:
+                raise
+            else:
+                LOGGER.warning(f'Resource {k} not added to OpenAPI: {err}')
+
+    LOGGER.debug('setting up STAC')
+    stac_collections = filter_dict_by_key_value(cfg['resources'],
+                                                'type', 'stac-collection')
+    if stac_collections:
+        paths['/stac'] = {
+            'get': {
+                'summary': 'SpatioTemporal Asset Catalog',
+                'description': 'SpatioTemporal Asset Catalog',
+                'tags': ['stac'],
+                'operationId': 'getStacCatalog',
+                'parameters': [],
+                'responses': {
+                    '200': {'$ref': '#/components/responses/200'},
+                    'default': {'$ref': '#/components/responses/default'}
+                }
+            }
         }
-        for link in l10n.translate(v.get('links', []), locale_):
-            if link['type'] == 'information':
-                tag['externalDocs']['description'] = link['type']
-                tag['externalDocs']['url'] = link['url']
-                break
-        if len(tag['externalDocs']) == 0:
-            del tag['externalDocs']
 
-        oas['tags'].append(tag)
+    process_manager = get_manager(cfg)
 
-        paths[collection_name_path] = {
+    if len(process_manager.processes) > 0:
+        paths['/processes'] = {
             'get': {
-                'summary': f'Get {title} metadata',
-                'description': desc,
-                'tags': [name],
-                'operationId': f'describe{name.capitalize()}Collection',
+                'summary': 'Processes',
+                'description': 'Processes',
+                'tags': ['server'],
+                'operationId': 'getProcesses',
                 'parameters': [
-                    {'$ref': '#/components/parameters/f'},
-                    {'$ref': '#/components/parameters/lang'}
+                    {'$ref': '#/components/parameters/f'}
                 ],
                 'responses': {
-                    '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Collection"},  # noqa
-                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                    '200': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ProcessList.yaml"},  # noqa
+                    'default': {'$ref': '#/components/responses/default'}
                 }
             }
         }
+        LOGGER.debug('setting up processes')
 
-        LOGGER.debug('setting up collection endpoints')
-        try:
-            ptype = None
-
-            if filter_providers_by_type(
-                    collections[k]['providers'], 'feature'):
-                ptype = 'feature'
-
-            if filter_providers_by_type(
-                    collections[k]['providers'], 'record'):
-                ptype = 'record'
-
-            p = load_plugin('provider', get_provider_by_type(
-                            collections[k]['providers'], ptype))
-
-            items_path = f'{collection_name_path}/items'
-
-            coll_properties = deepcopy(oas['components']['parameters']['properties'])  # noqa
+        for k, v in process_manager.processes.items():
+            if k.startswith('_'):
+                LOGGER.debug(f'Skipping hidden layer: {k}')
+                continue
+            name = l10n.translate(k, locale_)
+            p = process_manager.get_processor(k)
+            md_desc = l10n.translate(p.metadata['description'], locale_)
+            process_name_path = f'/processes/{name}'
+            tag = {
+                'name': name,
+                'description': md_desc,  # noqa
+                'externalDocs': {}
+            }
+            for link in p.metadata.get('links', []):
+                if link['type'] == 'information':
+                    translated_link = l10n.translate(link, locale_)
+                    tag['externalDocs']['description'] = translated_link[
+                        'type']
+                    tag['externalDocs']['url'] = translated_link['url']
+                    break
+            if len(tag['externalDocs']) == 0:
+                del tag['externalDocs']
 
-            coll_properties['schema']['items']['enum'] = list(p.fields.keys())
+            oas['tags'].append(tag)
 
-            paths[items_path] = {
+            paths[process_name_path] = {
                 'get': {
-                    'summary': f'Get {title} items',
-                    'description': desc,
+                    'summary': 'Get process metadata',
+                    'description': md_desc,
                     'tags': [name],
-                    'operationId': f'get{name.capitalize()}Features',
+                    'operationId': f'describe{name.capitalize()}Process',
                     'parameters': [
-                        items_f,
-                        items_l,
-                        {'$ref': '#/components/parameters/bbox'},
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/limit"},  # noqa
-                        {'$ref': '#/components/parameters/crs'},  # noqa
-                        {'$ref': '#/components/parameters/bbox-crs'},  # noqa
-                        coll_properties,
-                        {'$ref': '#/components/parameters/vendorSpecificParameters'},  # noqa
-                        {'$ref': '#/components/parameters/skipGeometry'},
-                        {'$ref': f"{OPENAPI_YAML['oapir']}/parameters/sortby.yaml"},  # noqa
-                        {'$ref': '#/components/parameters/offset'},
+                        {'$ref': '#/components/parameters/f'}
                     ],
                     'responses': {
-                        '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                    }
-                },
-                'options': {
-                    'summary': f'Options for {title} items',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'options{name.capitalize()}Features',
-                    'responses': {
-                        '200': {'description': 'options response'}
+                        '200': {'$ref': '#/components/responses/200'},
+                        'default': {'$ref': '#/components/responses/default'}
                     }
                 }
             }
 
-            if p.editable:
-                LOGGER.debug('Provider is editable; adding post')
-
-                paths[items_path]['post'] = {
-                    'summary': f'Add {title} items',
-                    'description': desc,
+            paths[f'{process_name_path}/execution'] = {
+                'post': {
+                    'summary': f"Process {l10n.translate(p.metadata['title'], locale_)} execution",  # noqa
+                    'description': md_desc,
                     'tags': [name],
-                    'operationId': f'add{name.capitalize()}Features',
+                    'operationId': f'execute{name.capitalize()}Job',
+                    'responses': {
+                        '200': {'$ref': '#/components/responses/200'},
+                        '201': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ExecuteAsync.yaml"},  # noqa
+                        '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                        '500': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ServerError.yaml"},  # noqa
+                        'default': {'$ref': '#/components/responses/default'}
+                    },
                     'requestBody': {
-                        'description': 'Adds item to collection',
+                        'description': 'Mandatory execute request JSON',
+                        'required': True,
                         'content': {
-                            'application/geo+json': {
-                                'schema': {}
+                            'application/json': {
+                                'schema': {
+                                    '$ref': f"{OPENAPI_YAML['oapip']}/schemas/execute.yaml"  # noqa
+                                }
                             }
-                        },
-                        'required': True
-                    },
-                    'responses': {
-                        '201': {'description': 'Successful creation'},
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                        }
                     }
                 }
+            }
+            if 'example' in p.metadata:
+                paths[f'{process_name_path}/execution']['post']['requestBody']['content']['application/json']['example'] = p.metadata['example']  # noqa
 
-                try:
-                    schema_ref = p.get_schema(SchemaType.create)
-                    paths[items_path]['post']['requestBody']['content'][schema_ref[0]] = {  # noqa
-                        'schema': schema_ref[1]
-                    }
-                except Exception as err:
-                    LOGGER.debug(err)
-
-            if ptype == 'record':
-                paths[items_path]['get']['parameters'].append(
-                    {'$ref': f"{OPENAPI_YAML['oapir']}/parameters/q.yaml"})
-            if p.fields:
-                schema_path = f'{collection_name_path}/schema'
-
-                paths[schema_path] = {
-                    'get': {
-                        'summary': f'Get {title} schema',
-                        'description': desc,
-                        'tags': [name],
-                        'operationId': f'get{name.capitalize()}Queryables',
-                        'parameters': [
-                            items_f,
-                            items_l
-                        ],
-                        'responses': {
-                            '200': {'$ref': '#/components/responses/Queryables'},  # noqa
-                            '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                            '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                            '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
-                        }
-                    }
+            name_in_path = {
+                'name': 'jobId',
+                'in': 'path',
+                'description': 'job identifier',
+                'required': True,
+                'schema': {
+                    'type': 'string'
                 }
+            }
 
-                queryables_path = f'{collection_name_path}/queryables'
-
-                paths[queryables_path] = {
-                    'get': {
-                        'summary': f'Get {title} queryables',
-                        'description': desc,
-                        'tags': [name],
-                        'operationId': f'get{name.capitalize()}Queryables',
-                        'parameters': [
-                            items_f,
-                            items_l
-                        ],
-                        'responses': {
-                            '200': {'$ref': '#/components/responses/Queryables'},  # noqa
-                            '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                            '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                            '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
-                        }
-                    }
+        paths['/jobs'] = {
+            'get': {
+                'summary': 'Retrieve jobs list',
+                'description': 'Retrieve a list of jobs',
+                'tags': ['jobs'],
+                'operationId': 'getJobs',
+                'responses': {
+                    '200': {'$ref': '#/components/responses/200'},
+                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                    'default': {'$ref': '#/components/responses/default'}
                 }
+            }
+        }
 
-            if p.time_field is not None:
-                paths[items_path]['get']['parameters'].append(
-                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"})  # noqa
+        paths['/jobs/{jobId}'] = {
+            'get': {
+                'summary': 'Retrieve job details',
+                'description': 'Retrieve job details',
+                'tags': ['jobs'],
+                'parameters': [
+                    name_in_path,
+                    {'$ref': '#/components/parameters/f'}
+                ],
+                'operationId': 'getJob',
+                'responses': {
+                    '200': {'$ref': '#/components/responses/200'},
+                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                }
+            },
+            'delete': {
+                'summary': 'Cancel / delete job',
+                'description': 'Cancel / delete job',
+                'tags': ['jobs'],
+                'parameters': [
+                    name_in_path
+                ],
+                'operationId': 'deleteJob',
+                'responses': {
+                    '204': {'$ref': '#/components/responses/204'},
+                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                }
+            },
+        }
 
-            for field, type_ in p.fields.items():
+        paths['/jobs/{jobId}/results'] = {
+            'get': {
+                'summary': 'Retrieve job results',
+                'description': 'Retrive job resiults',
+                'tags': ['jobs'],
+                'parameters': [
+                    name_in_path,
+                    {'$ref': '#/components/parameters/f'}
+                ],
+                'operationId': 'getJobResults',
+                'responses': {
+                    '200': {'$ref': '#/components/responses/200'},
+                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                }
+            }
+        }
 
-                if p.properties and field not in p.properties:
-                    LOGGER.debug('Provider specified not to advertise property')  # noqa
-                    continue
+        tag = {
+            'name': 'jobs',
+            'description': 'Process jobs',
+        }
+        oas['tags'].insert(1, tag)
 
-                if field == 'q' and ptype == 'record':
-                    LOGGER.debug('q parameter already declared, skipping')
-                    continue
+    oas['paths'] = paths
 
-                if type_ == 'date':
-                    schema = {
-                        'type': 'string',
-                        'format': 'date'
-                    }
-                elif type_ == 'float':
-                    schema = {
-                        'type': 'number',
-                        'format': 'float'
-                    }
-                elif type_ == 'long':
-                    schema = {
-                        'type': 'integer',
-                        'format': 'int64'
-                    }
-                else:
-                    schema = type_
+    if cfg['server'].get('admin', False):
+        schema_dict = get_config_schema()
+        oas['definitions'] = schema_dict['definitions']
+        LOGGER.debug('Adding admin endpoints')
+        oas['paths'].update(get_admin())
 
-                path_ = f'{collection_name_path}/items'
-                paths[path_]['get']['parameters'].append({
-                    'name': field,
-                    'in': 'query',
-                    'required': False,
-                    'schema': schema,
-                    'style': 'form',
-                    'explode': False
-                })
+    return oas
 
-            paths[f'{collection_name_path}/items/{{featureId}}'] = {
-                'get': {
-                    'summary': f'Get {title} item by id',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'get{name.capitalize()}Feature',
-                    'parameters': [
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"},  # noqa
-                        {'$ref': '#/components/parameters/crs'},  # noqa
-                        {'$ref': '#/components/parameters/f'},
-                        {'$ref': '#/components/parameters/lang'}
-                    ],
-                    'responses': {
-                        '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Feature"},  # noqa
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                    }
-                },
-                'options': {
-                    'summary': f'Options for {title} item by id',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'options{name.capitalize()}Feature',
-                    'parameters': [
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"}  # noqa
-                    ],
-                    'responses': {
-                        '200': {'description': 'options response'}
-                    }
-                }
-            }
 
-            try:
-                schema_ref = p.get_schema()
-                paths[f'{collection_name_path}/items/{{featureId}}']['get']['responses']['200'] = {  # noqa
-                    'content': {
-                        schema_ref[0]: {
-                            'schema': schema_ref[1]
-                        }
-                    }
-                }
-            except Exception as err:
-                LOGGER.debug(err)
+def get_config_schema() -> dict:
+    """
+    Get configuration schema
 
-            if p.editable:
-                LOGGER.debug('Provider is editable; adding put/delete')
-                put_path = f'{collection_name_path}/items/{{featureId}}'  # noqa
-                paths[put_path]['put'] = {  # noqa
-                    'summary': f'Update {title} items',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'update{name.capitalize()}Features',
-                    'parameters': [
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"}  # noqa
-                    ],
-                    'requestBody': {
-                        'description': 'Updates item in collection',
-                        'content': {
-                            'application/geo+json': {
-                                'schema': {}
-                            }
-                        },
-                        'required': True
-                    },
-                    'responses': {
-                        '204': {'$ref': '#/components/responses/204'},
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                    }
-                }
+    :returns: `dict` of configuration schema
+    """
 
-                try:
-                    schema_ref = p.get_schema(SchemaType.replace)
-                    paths[put_path]['put']['requestBody']['content'][schema_ref[0]] = {  # noqa
-                        'schema': schema_ref[1]
-                    }
-                except Exception as err:
-                    LOGGER.debug(err)
+    schema_file = os.path.join(THISDIR, 'schemas', 'config',
+                               'pygeoapi-config-0.x.yml')
 
-                paths[f'{collection_name_path}/items/{{featureId}}']['delete'] = {  # noqa
-                    'summary': f'Delete {title} items',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'delete{name.capitalize()}Features',
-                    'parameters': [
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"},  # noqa
-                    ],
-                    'responses': {
-                        '200': {'description': 'Successful delete'},
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                    }
-                }
+    with open(schema_file) as fh2:
+        return yaml_load(fh2)
 
-        except ProviderTypeError:
-            LOGGER.debug('collection is not feature based')
 
-        LOGGER.debug('setting up coverage endpoints')
-        try:
-            load_plugin('provider', get_provider_by_type(
-                        collections[k]['providers'], 'coverage'))
-
-            coverage_path = f'{collection_name_path}/coverage'
+def get_admin() -> dict:
+    """
+    Generate admin paths for OpenAPI Document
 
-            paths[coverage_path] = {
-                'get': {
-                    'summary': f'Get {title} coverage',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'get{name.capitalize()}Coverage',
-                    'parameters': [
-                        items_f,
-                        items_l,
-                        {'$ref': '#/components/parameters/bbox'},
-                        {'$ref': '#/components/parameters/bbox-crs'},  # noqa
-                    ],
-                    'responses': {
-                        '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                    }
-                }
-            }
+    :returns: `dict` of paths
+    """
 
-        except ProviderTypeError:
-            LOGGER.debug('collection is not coverage based')
+    schema_dict = get_config_schema()
 
-        LOGGER.debug('setting up tiles endpoints')
-        tile_extension = filter_providers_by_type(
-            collections[k]['providers'], 'tile')
+    paths = {}
 
-        if tile_extension:
-            tp = load_plugin('provider', tile_extension)
-            oas['components']['responses'].update({
-                    'Tiles': {
-                        'description': 'Retrieves the tiles description for this collection', # noqa
-                        'content': {
-                            'application/json': {
-                                'schema': {
-                                    '$ref': '#/components/schemas/tiles'
-                                }
-                            }
+    paths['/admin/config'] = {
+        'get': {
+            'summary': 'Get admin configuration',
+            'description': 'Get admin configuration',
+            'tags': ['admin'],
+            'operationId': 'getAdminConfig',
+            'parameters': [
+                {'$ref': '#/components/parameters/f'},
+                {'$ref': '#/components/parameters/lang'}
+            ],
+            'responses': {
+                '200': {
+                    'content': {
+                        'application/json': {
+                            'schema': schema_dict
                         }
                     }
                 }
-            )
-
-            oas['components']['schemas'].update({
-                    'tilematrixsetlink': {
-                        'type': 'object',
-                        'required': ['tileMatrixSet'],
-                        'properties': {
-                            'tileMatrixSet': {
-                                'type': 'string'
-                            },
-                            'tileMatrixSetURI': {
-                                'type': 'string'
-                            }
-                        }
-                    },
-                    'tiles': {
-                        'type': 'object',
-                        'required': [
-                            'tileMatrixSetLinks',
-                            'links'
-                        ],
-                        'properties': {
-                            'tileMatrixSetLinks': {
-                                'type': 'array',
-                                'items': {
-                                    '$ref': '#/components/schemas/tilematrixsetlink' # noqa
-                                }
-                            },
-                            'links': {
-                                'type': 'array',
-                                'items': {'$ref': f"{OPENAPI_YAML['oapit']}#/components/schemas/link"}  # noqa
-                            }
-                        }
+            }
+        },
+        'put': {
+            'summary': 'Update admin configuration full',
+            'description': 'Update admin configuration full',
+            'tags': ['admin'],
+            'operationId': 'putAdminConfig',
+            'requestBody': {
+                'description': 'Updates admin configuration',
+                'content': {
+                    'application/json': {
+                        'schema': schema_dict
                     }
-                }
-            )
-
-            tiles_path = f'{collection_name_path}/tiles'
-
-            paths[tiles_path] = {
-                'get': {
-                    'summary': f'Fetch a {title} tiles description',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'describe{name.capitalize()}Tiles',
-                    'parameters': [
-                        items_f,
-                        # items_l  TODO: is this useful?
-                    ],
-                    'responses': {
-                        '200': {'$ref': '#/components/responses/Tiles'},
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                },
+                'required': True
+            },
+            'responses': {
+                '204': {'$ref': '#/components/responses/204'},
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+            }
+        },
+        'patch': {
+            'summary': 'Partially update admin configuration',
+            'description': 'Partially update admin configuration',
+            'tags': ['admin'],
+            'operationId': 'patchAdminConfig',
+            'requestBody': {
+                'description': 'Updates admin configuration',
+                'content': {
+                    'application/json': {
+                        'schema': schema_dict
                     }
-                }
+                },
+                'required': True
+            },
+            'responses': {
+                '204': {'$ref': '#/components/responses/204'},
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
             }
-
-            tiles_data_path = f'{collection_name_path}/tiles/{{tileMatrixSetId}}/{{tileMatrix}}/{{tileRow}}/{{tileCol}}'  # noqa
-
-            paths[tiles_data_path] = {
-                'get': {
-                    'summary': f'Get a {title} tile',
-                    'description': desc,
-                    'tags': [name],
-                    'operationId': f'get{name.capitalize()}Tiles',
-                    'parameters': [
-                        {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileMatrixSetId"}, # noqa
-                        {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileMatrix"},  # noqa
-                        {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileRow"},  # noqa
-                        {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileCol"},  # noqa
-                        {
-                            'name': 'f',
-                            'in': 'query',
-                            'description': 'The optional f parameter indicates the output format which the server shall provide as part of the response document.',  # noqa
-                            'required': False,
-                            'schema': {
-                                'type': 'string',
-                                'enum': [tp.format_type],
-                                'default': tp.format_type
-                            },
-                            'style': 'form',
-                            'explode': False
+        }
+    }
+    paths['/admin/config/resources'] = {
+        'get': {
+            'summary': 'Get admin configuration resources',
+            'description': 'Get admin configuration resources',
+            'tags': ['admin'],
+            'operationId': 'getAdminConfigResources',
+            'parameters': [
+                {'$ref': '#/components/parameters/f'},
+                {'$ref': '#/components/parameters/lang'}
+            ],
+            'responses': {
+                '200': {
+                    'content': {
+                        'application/json': {
+                            'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
                         }
-                    ],
-                    'responses': {
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
                     }
                 }
             }
-            mimetype = tile_extension['format']['mimetype']
-            paths[tiles_data_path]['get']['responses']['200'] = {
-                'description': 'successful operation',
+        },
+        'post': {
+            'summary': 'Create admin configuration resource',
+            'description': 'Create admin configuration resource',
+            'tags': ['admin'],
+            'operationId': 'postAdminConfigResource',
+            'requestBody': {
+                'description': 'Adds resource to configuration',
                 'content': {
-                    mimetype: {
-                        'schema': {
-                            'type': 'string',
-                            'format': 'binary'
+                    'application/json': {
+                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+                    }
+                },
+                'required': True
+            },
+            'responses': {
+                '201': {'description': 'Successful creation'},
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+            }
+        },
+    }
+    paths['/admin/config/resources/{resourceId}'] = {
+        'get': {
+            'summary': 'Get admin configuration resource',
+            'description': 'Get admin configuration resource',
+            'tags': ['admin'],
+            'operationId': 'getAdminConfigResource',
+            'parameters': [
+                {'$ref': '#/components/parameters/resourceId'},
+                {'$ref': '#/components/parameters/f'},
+                {'$ref': '#/components/parameters/lang'}
+            ],
+            'responses': {
+                '200': {
+                    'content': {
+                        'application/json': {
+                            'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
                         }
                     }
                 }
             }
+        },
+        'put': {
+            'summary': 'Update admin configuration resource',
+            'description': 'Update admin configuration resource',
+            'tags': ['admin'],
+            'operationId': 'putAdminConfigResource',
+            'parameters': [
+                {'$ref': '#/components/parameters/resourceId'},
+            ],
+            'requestBody': {
+                'description': 'Updates admin configuration resource',
+                'content': {
+                    'application/json': {
+                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+                    }
+                },
+                'required': True
+            },
+            'responses': {
+                '204': {'$ref': '#/components/responses/204'},
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+            }
+        },
+        'patch': {
+            'summary': 'Partially update admin configuration resource',
+            'description': 'Partially update admin configuration resource',
+            'tags': ['admin'],
+            'operationId': 'patchAdminConfigResource',
+            'parameters': [
+                {'$ref': '#/components/parameters/resourceId'},
+            ],
+            'requestBody': {
+                'description': 'Updates admin configuration resource',
+                'content': {
+                    'application/json': {
+                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+                    }
+                },
+                'required': True
+            },
+            'responses': {
+                '204': {'$ref': '#/components/responses/204'},
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+            }
+        },
+        'delete': {
+            'summary': 'Delete admin configuration resource',
+            'description': 'Delete admin configuration resource',
+            'tags': ['admin'],
+            'operationId': 'deleteAdminConfigResource',
+            'parameters': [
+                {'$ref': '#/components/parameters/resourceId'},
+            ],
+            'responses': {
+                '204': {'$ref': '#/components/responses/204'},
+                '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
+                'default': {'$ref': '#/components/responses/default'}  # noqa
+            }
+        }
+    }
 
-        LOGGER.debug('setting up edr endpoints')
-        edr_extension = filter_providers_by_type(
-            collections[k]['providers'], 'edr')
+    return paths
 
-        if edr_extension:
-            ep = load_plugin('provider', edr_extension)
 
-            edr_query_endpoints = []
+def handle_collection(locale_: str, components: dict, collection_id: str,
+                      collection_def: dict) -> Tuple[list, dict]:
+    """
+    Generate relevant OpenAPI constructs for a given collection
 
-            for qt in [qt for qt in ep.get_query_types() if qt != 'locations']:
-                edr_query_endpoints.append({
-                    'path': f'{collection_name_path}/{qt}',
-                    'qt': qt,
-                    'op_id': f'query{qt.capitalize()}{k.capitalize()}'
-                })
-                if ep.instances:
-                    edr_query_endpoints.append({
-                        'path': f'{collection_name_path}/instances/{{instanceId}}/{qt}',  # noqa
-                        'qt': qt,
-                        'op_id': f'query{qt.capitalize()}Instance{k.capitalize()}'  # noqa
-                    })
-
-            for eqe in edr_query_endpoints:
-                if eqe['qt'] == 'cube':
-                    spatial_parameter = 'bbox'
-                else:
-                    spatial_parameter = f"{eqe['qt']}Coords"
-                paths[eqe['path']] = {
-                    'get': {
-                        'summary': f"query {v['description']} by {eqe['qt']}",  # noqa
-                        'description': v['description'],
-                        'tags': [k],
-                        'operationId': eqe['op_id'],
-                        'parameters': [
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/{spatial_parameter}.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/parameter-name.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/z.yaml"},  # noqa
-                            {'$ref': '#/components/parameters/f'}
-                        ],
-                        'responses': {
-                            '200': {
-                                'description': 'Response',
-                                'content': {
-                                    'application/prs.coverage+json': {
-                                        'schema': {
-                                            '$ref': f"{OPENAPI_YAML['oaedr']}/schemas/coverageJSON.yaml"  # noqa
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            if 'locations' in ep.get_query_types():
-                paths[f'{collection_name_path}/locations'] = {
-                    'get': {
-                        'summary': f"Get pre-defined locations of {v['description']}",  # noqa
-                        'description': v['description'],
-                        'tags': [k],
-                        'operationId': f'queryLOCATIONS{k.capitalize()}',
-                        'parameters': [
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/bbox.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
-                            {'$ref': '#/components/parameters/f'}
-                        ],
-                        'responses': {
-                            '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
-                            '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                            '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-                        }
-                    }
-                }
-                paths[f'{collection_name_path}/locations/{{locId}}'] = {
-                    'get': {
-                        'summary': f"query {v['description']} by location",  # noqa
-                        'description': v['description'],
-                        'tags': [k],
-                        'operationId': f'queryLOCATIONSBYID{k.capitalize()}',
-                        'parameters': [
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/{spatial_parameter}.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/locationId.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/parameter-name.yaml"},  # noqa
-                            {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/z.yaml"},  # noqa
-                            {'$ref': '#/components/parameters/f'}
-                        ],
-                        'responses': {
-                            '200': {
-                                'description': 'Response',
-                                'content': {
-                                    'application/prs.coverage+json': {
-                                        'schema': {
-                                            '$ref': f"{OPENAPI_YAML['oaedr']}/schemas/coverageJSON.yaml"  # noqa
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+    :param locale_: locale
+    :param components: OpenAPI components
+    :param collection_id: collection identifier
+    :param collection_def: collection definition
 
-        LOGGER.debug('setting up maps endpoints')
-        map_extension = filter_providers_by_type(
-            collections[k]['providers'], 'map')
+    :returns: `tuple` of `list` of tags and `dict` of paths
+    """
 
-        if map_extension:
-            mp = load_plugin('provider', map_extension)
+    paths = {}
+    tags = []
 
-            map_f = deepcopy(oas['components']['parameters']['f'])
-            map_f['schema']['enum'] = [map_extension['format']['name']]
-            map_f['schema']['default'] = map_extension['format']['name']
+    items_f = deepcopy(components['parameters']['f'])
+    items_f['schema']['enum'].append('csv')
+    items_l = deepcopy(components['parameters']['lang'])
 
-            pth = f'/collections/{k}/map'
-            paths[pth] = {
-                'get': {
-                    'summary': 'Get map',
-                    'description': f"{v['description']} map",
-                    'tags': [k],
-                    'operationId': 'getMap',
-                    'parameters': [
-                        {'$ref': '#/components/parameters/bbox'},
-                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
-                        {
-                            'name': 'width',
-                            'in': 'query',
-                            'description': 'Response image width',
-                            'required': False,
-                            'schema': {
-                                'type': 'integer',
-                            },
-                            'style': 'form',
-                            'explode': False
-                        },
-                        {
-                            'name': 'height',
-                            'in': 'query',
-                            'description': 'Response image height',
-                            'required': False,
-                            'schema': {
-                                'type': 'integer',
-                            },
-                            'style': 'form',
-                            'explode': False
-                        },
-                        {
-                            'name': 'transparent',
-                            'in': 'query',
-                            'description': 'Background transparency of map (default=true).',  # noqa
-                            'required': False,
-                            'schema': {
-                                'type': 'boolean',
-                                'default': True,
-                            },
-                            'style': 'form',
-                            'explode': False
-                        },
-                        {'$ref': '#/components/parameters/bbox-crs-epsg'},
-                        map_f
-                    ],
-                    'responses': {
-                        '200': {
-                            'description': 'Response',
-                            'content': {
-                                'application/json': {}
-                            }
-                        },
-                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
-                    }
-                }
-            }
-            if mp.time_field is not None:
-                paths[pth]['get']['parameters'].append(
-                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"})  # noqa
+    if collection_def.get('visibility', 'default') == 'hidden':
+        LOGGER.debug(f'Skipping hidden layer: {collection_id}')
+        return [], {}
 
-    LOGGER.debug('setting up STAC')
-    stac_collections = filter_dict_by_key_value(cfg['resources'],
-                                                'type', 'stac-collection')
-    if stac_collections:
-        paths['/stac'] = {
-            'get': {
-                'summary': 'SpatioTemporal Asset Catalog',
-                'description': 'SpatioTemporal Asset Catalog',
-                'tags': ['stac'],
-                'operationId': 'getStacCatalog',
-                'parameters': [],
-                'responses': {
-                    '200': {'$ref': '#/components/responses/200'},
-                    'default': {'$ref': '#/components/responses/default'}
-                }
+    name = l10n.translate(collection_id, locale_)
+    title = l10n.translate(collection_def['title'], locale_)
+    desc = l10n.translate(collection_def['description'], locale_)
+    collection_name_path = f'/collections/{collection_id}'
+
+    tag = {
+        'name': name,
+        'description': desc,
+        'externalDocs': {}
+    }
+
+    for link in l10n.translate(collection_def.get('links', []), locale_):
+        if link['type'] == 'information':
+            tag['externalDocs']['description'] = link['type']
+            tag['externalDocs']['url'] = link['url']
+            break
+
+    if len(tag['externalDocs']) == 0:
+        del tag['externalDocs']
+
+    tags.append(tag)
+
+    paths[collection_name_path] = {
+        'get': {
+            'summary': f'Get {title} metadata',
+            'description': desc,
+            'tags': [name],
+            'operationId': f'describe{name.capitalize()}Collection',
+            'parameters': [
+                {'$ref': '#/components/parameters/f'},
+                {'$ref': '#/components/parameters/lang'}
+            ],
+            'responses': {
+                '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Collection"},  # noqa
+                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
             }
         }
+    }
 
-    process_manager = get_manager(cfg)
+    LOGGER.debug('setting up collection endpoints')
+    try:
+        ptype = None
 
-    if len(process_manager.processes) > 0:
-        paths['/processes'] = {
+        if filter_providers_by_type(collection_def['providers'], 'feature'):
+            ptype = 'feature'
+
+        if filter_providers_by_type(collection_def['providers'], 'record'):
+            ptype = 'record'
+
+        p = load_plugin('provider', get_provider_by_type(
+                        collection_def['providers'], ptype))
+
+        items_path = f'{collection_name_path}/items'
+
+        coll_properties = deepcopy(components['parameters']['properties'])  # noqa
+
+        coll_properties['schema']['items']['enum'] = list(p.fields.keys())
+
+        paths[items_path] = {
             'get': {
-                'summary': 'Processes',
-                'description': 'Processes',
-                'tags': ['server'],
-                'operationId': 'getProcesses',
+                'summary': f'Get {title} items',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'get{name.capitalize()}Features',
                 'parameters': [
-                    {'$ref': '#/components/parameters/f'}
+                    items_f,
+                    items_l,
+                    {'$ref': '#/components/parameters/bbox'},
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/limit"},  # noqa
+                    {'$ref': '#/components/parameters/crs'},  # noqa
+                    {'$ref': '#/components/parameters/bbox-crs'},  # noqa
+                    coll_properties,
+                    {'$ref': '#/components/parameters/vendorSpecificParameters'},  # noqa
+                    {'$ref': '#/components/parameters/skipGeometry'},
+                    {'$ref': f"{OPENAPI_YAML['oapir']}/parameters/sortby.yaml"},  # noqa
+                    {'$ref': '#/components/parameters/offset'},
                 ],
                 'responses': {
-                    '200': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ProcessList.yaml"},  # noqa
-                    'default': {'$ref': '#/components/responses/default'}
+                    '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
+            },
+            'options': {
+                'summary': f'Options for {title} items',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'options{name.capitalize()}Features',
+                'responses': {
+                    '200': {'description': 'options response'}
                 }
             }
         }
-        LOGGER.debug('setting up processes')
 
-        for k, v in process_manager.processes.items():
-            if k.startswith('_'):
-                LOGGER.debug(f'Skipping hidden layer: {k}')
-                continue
-            name = l10n.translate(k, locale_)
-            p = process_manager.get_processor(k)
-            md_desc = l10n.translate(p.metadata['description'], locale_)
-            process_name_path = f'/processes/{name}'
-            tag = {
-                'name': name,
-                'description': md_desc,  # noqa
-                'externalDocs': {}
+        if p.editable:
+            LOGGER.debug('Provider is editable; adding post')
+
+            paths[items_path]['post'] = {
+                'summary': f'Add {title} items',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'add{name.capitalize()}Features',
+                'requestBody': {
+                    'description': 'Adds item to collection',
+                    'content': {
+                        'application/geo+json': {
+                            'schema': {}
+                        }
+                    },
+                    'required': True
+                },
+                'responses': {
+                    '201': {'description': 'Successful creation'},
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
             }
-            for link in p.metadata.get('links', []):
-                if link['type'] == 'information':
-                    translated_link = l10n.translate(link, locale_)
-                    tag['externalDocs']['description'] = translated_link[
-                        'type']
-                    tag['externalDocs']['url'] = translated_link['url']
-                    break
-            if len(tag['externalDocs']) == 0:
-                del tag['externalDocs']
 
-            oas['tags'].append(tag)
+            try:
+                schema_ref = p.get_schema(SchemaType.create)
+                paths[items_path]['post']['requestBody']['content'][schema_ref[0]] = {  # noqa
+                    'schema': schema_ref[1]
+                }
+            except Exception as err:
+                LOGGER.debug(err)
 
-            paths[process_name_path] = {
+        if ptype == 'record':
+            paths[items_path]['get']['parameters'].append(
+                {'$ref': f"{OPENAPI_YAML['oapir']}/parameters/q.yaml"})
+        if p.fields:
+            schema_path = f'{collection_name_path}/schema'
+
+            paths[schema_path] = {
                 'get': {
-                    'summary': 'Get process metadata',
-                    'description': md_desc,
+                    'summary': f'Get {title} schema',
+                    'description': desc,
                     'tags': [name],
-                    'operationId': f'describe{name.capitalize()}Process',
+                    'operationId': f'get{name.capitalize()}Queryables',
                     'parameters': [
-                        {'$ref': '#/components/parameters/f'}
+                        items_f,
+                        items_l
                     ],
                     'responses': {
-                        '200': {'$ref': '#/components/responses/200'},
-                        'default': {'$ref': '#/components/responses/default'}
+                        '200': {'$ref': '#/components/responses/Queryables'},  # noqa
+                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
                     }
                 }
             }
 
-            paths[f'{process_name_path}/execution'] = {
-                'post': {
-                    'summary': f"Process {l10n.translate(p.metadata['title'], locale_)} execution",  # noqa
-                    'description': md_desc,
+            queryables_path = f'{collection_name_path}/queryables'
+
+            paths[queryables_path] = {
+                'get': {
+                    'summary': f'Get {title} queryables',
+                    'description': desc,
                     'tags': [name],
-                    'operationId': f'execute{name.capitalize()}Job',
+                    'operationId': f'get{name.capitalize()}Queryables',
+                    'parameters': [
+                        items_f,
+                        items_l
+                    ],
                     'responses': {
-                        '200': {'$ref': '#/components/responses/200'},
-                        '201': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ExecuteAsync.yaml"},  # noqa
-                        '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                        '500': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/ServerError.yaml"},  # noqa
-                        'default': {'$ref': '#/components/responses/default'}
-                    },
-                    'requestBody': {
-                        'description': 'Mandatory execute request JSON',
-                        'required': True,
-                        'content': {
-                            'application/json': {
-                                'schema': {
-                                    '$ref': f"{OPENAPI_YAML['oapip']}/schemas/execute.yaml"  # noqa
-                                }
-                            }
-                        }
+                        '200': {'$ref': '#/components/responses/Queryables'},
+                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                        '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
                     }
                 }
             }
-            if 'example' in p.metadata:
-                paths[f'{process_name_path}/execution']['post']['requestBody']['content']['application/json']['example'] = p.metadata['example']  # noqa
 
-            name_in_path = {
-                'name': 'jobId',
-                'in': 'path',
-                'description': 'job identifier',
-                'required': True,
-                'schema': {
-                    'type': 'string'
-                }
-            }
+        if p.time_field is not None:
+            paths[items_path]['get']['parameters'].append(
+                {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"})  # noqa
 
-        paths['/jobs'] = {
-            'get': {
-                'summary': 'Retrieve jobs list',
-                'description': 'Retrieve a list of jobs',
-                'tags': ['jobs'],
-                'operationId': 'getJobs',
-                'responses': {
-                    '200': {'$ref': '#/components/responses/200'},
-                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                    'default': {'$ref': '#/components/responses/default'}
+        for field, type_ in p.fields.items():
+
+            if p.properties and field not in p.properties:
+                LOGGER.debug('Provider specified not to advertise property')
+                continue
+
+            if field == 'q' and ptype == 'record':
+                LOGGER.debug('q parameter already declared, skipping')
+                continue
+
+            if type_ == 'date':
+                schema = {
+                    'type': 'string',
+                    'format': 'date'
                 }
-            }
-        }
+            elif type_ == 'float':
+                schema = {
+                    'type': 'number',
+                    'format': 'float'
+                }
+            elif type_ == 'long':
+                schema = {
+                    'type': 'integer',
+                    'format': 'int64'
+                }
+            else:
+                schema = type_
 
-        paths['/jobs/{jobId}'] = {
+            path_ = f'{collection_name_path}/items'
+            paths[path_]['get']['parameters'].append({
+                'name': field,
+                'in': 'query',
+                'required': False,
+                'schema': schema,
+                'style': 'form',
+                'explode': False
+            })
+
+        paths[f'{collection_name_path}/items/{{featureId}}'] = {
             'get': {
-                'summary': 'Retrieve job details',
-                'description': 'Retrieve job details',
-                'tags': ['jobs'],
+                'summary': f'Get {title} item by id',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'get{name.capitalize()}Feature',
                 'parameters': [
-                    name_in_path,
-                    {'$ref': '#/components/parameters/f'}
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"},  # noqa
+                    {'$ref': '#/components/parameters/crs'},  # noqa
+                    {'$ref': '#/components/parameters/f'},
+                    {'$ref': '#/components/parameters/lang'}
                 ],
-                'operationId': 'getJob',
                 'responses': {
-                    '200': {'$ref': '#/components/responses/200'},
-                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                    '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Feature"},  # noqa
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
                 }
             },
-            'delete': {
-                'summary': 'Cancel / delete job',
-                'description': 'Cancel / delete job',
-                'tags': ['jobs'],
+            'options': {
+                'summary': f'Options for {title} item by id',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'options{name.capitalize()}Feature',
                 'parameters': [
-                    name_in_path
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"}  # noqa
                 ],
-                'operationId': 'deleteJob',
                 'responses': {
-                    '204': {'$ref': '#/components/responses/204'},
-                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                    '200': {'description': 'options response'}
                 }
-            },
+            }
         }
 
-        paths['/jobs/{jobId}/results'] = {
-            'get': {
-                'summary': 'Retrieve job results',
-                'description': 'Retrive job resiults',
-                'tags': ['jobs'],
+        try:
+            schema_ref = p.get_schema()
+            paths[f'{collection_name_path}/items/{{featureId}}']['get']['responses']['200'] = {  # noqa
+                'content': {
+                    schema_ref[0]: {
+                        'schema': schema_ref[1]
+                    }
+                }
+            }
+        except Exception as err:
+            LOGGER.debug(err)
+
+        if p.editable:
+            LOGGER.debug('Provider is editable; adding put/delete')
+            put_path = f'{collection_name_path}/items/{{featureId}}'
+            paths[put_path]['put'] = {  # noqa
+                'summary': f'Update {title} items',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'update{name.capitalize()}Features',
                 'parameters': [
-                    name_in_path,
-                    {'$ref': '#/components/parameters/f'}
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"}  # noqa
                 ],
-                'operationId': 'getJobResults',
+                'requestBody': {
+                    'description': 'Updates item in collection',
+                    'content': {
+                        'application/geo+json': {
+                            'schema': {}
+                        }
+                    },
+                    'required': True
+                },
                 'responses': {
-                    '200': {'$ref': '#/components/responses/200'},
-                    '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                    'default': {'$ref': '#/components/responses/default'}  # noqa
+                    '204': {'$ref': '#/components/responses/204'},
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
                 }
             }
-        }
 
-        tag = {
-            'name': 'jobs',
-            'description': 'Process jobs',
-        }
-        oas['tags'].insert(1, tag)
+            try:
+                schema_ref = p.get_schema(SchemaType.replace)
+                paths[put_path]['put']['requestBody']['content'][schema_ref[0]] = {  # noqa
+                    'schema': schema_ref[1]
+                }
+            except Exception as err:
+                LOGGER.debug(err)
 
-    oas['paths'] = paths
+            paths[f'{collection_name_path}/items/{{featureId}}']['delete'] = {
+                'summary': f'Delete {title} items',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'delete{name.capitalize()}Features',
+                'parameters': [
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/featureId"},  # noqa
+                ],
+                'responses': {
+                    '200': {'description': 'Successful delete'},
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
+            }
 
-    if cfg['server'].get('admin', False):
-        schema_dict = get_config_schema()
-        oas['definitions'] = schema_dict['definitions']
-        LOGGER.debug('Adding admin endpoints')
-        oas['paths'].update(get_admin())
+    except ProviderTypeError:
+        LOGGER.debug('collection is not feature based')
 
-    return oas
+    LOGGER.debug('setting up coverage endpoints')
+    try:
+        load_plugin('provider', get_provider_by_type(
+                    collection_def['providers'], 'coverage'))
 
+        coverage_path = f'{collection_name_path}/coverage'
 
-def get_config_schema():
-    schema_file = os.path.join(THISDIR, 'schemas', 'config',
-                               'pygeoapi-config-0.x.yml')
+        paths[coverage_path] = {
+            'get': {
+                'summary': f'Get {title} coverage',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'get{name.capitalize()}Coverage',
+                'parameters': [
+                    items_f,
+                    items_l,
+                    {'$ref': '#/components/parameters/bbox'},
+                    {'$ref': '#/components/parameters/bbox-crs'},
+                ],
+                'responses': {
+                    '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
+            }
+        }
 
-    with open(schema_file) as fh2:
-        return yaml_load(fh2)
+    except ProviderTypeError:
+        LOGGER.debug('collection is not coverage based')
 
+    LOGGER.debug('setting up tiles endpoints')
+    tile_extension = filter_providers_by_type(
+        collection_def['providers'], 'tile')
 
-def get_admin():
+    if tile_extension:
+        tp = load_plugin('provider', tile_extension)
 
-    schema_dict = get_config_schema()
+        tiles_path = f'{collection_name_path}/tiles'
+
+        paths[tiles_path] = {
+            'get': {
+                'summary': f'Fetch a {title} tiles description',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'describe{name.capitalize()}Tiles',
+                'parameters': [
+                    items_f,
+                    # items_l  TODO: is this useful?
+                ],
+                'responses': {
+                    '200': {'$ref': '#/components/responses/Tiles'},
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
+            }
+        }
 
-    paths = {}
+        tiles_data_path = f'{collection_name_path}/tiles/{{tileMatrixSetId}}/{{tileMatrix}}/{{tileRow}}/{{tileCol}}'  # noqa
 
-    paths['/admin/config'] = {
-        'get': {
-            'summary': 'Get admin configuration',
-            'description': 'Get admin configuration',
-            'tags': ['admin'],
-            'operationId': 'getAdminConfig',
-            'parameters': [
-                {'$ref': '#/components/parameters/f'},
-                {'$ref': '#/components/parameters/lang'}
-            ],
-            'responses': {
-                '200': {
-                    'content': {
-                        'application/json': {
-                            'schema': schema_dict
-                        }
+        paths[tiles_data_path] = {
+            'get': {
+                'summary': f'Get a {title} tile',
+                'description': desc,
+                'tags': [name],
+                'operationId': f'get{name.capitalize()}Tiles',
+                'parameters': [
+                    {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileMatrixSetId"}, # noqa
+                    {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileMatrix"},  # noqa
+                    {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileRow"},  # noqa
+                    {'$ref': f"{OPENAPI_YAML['oapit']}#/components/parameters/tileCol"},  # noqa
+                    {
+                        'name': 'f',
+                        'in': 'query',
+                        'description': 'The optional f parameter indicates the output format which the server shall provide as part of the response document.',  # noqa
+                        'required': False,
+                        'schema': {
+                            'type': 'string',
+                            'enum': [tp.format_type],
+                            'default': tp.format_type
+                        },
+                        'style': 'form',
+                        'explode': False
                     }
+                ],
+                'responses': {
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '404': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/NotFound"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
                 }
             }
-        },
-        'put': {
-            'summary': 'Update admin configuration full',
-            'description': 'Update admin configuration full',
-            'tags': ['admin'],
-            'operationId': 'putAdminConfig',
-            'requestBody': {
-                'description': 'Updates admin configuration',
-                'content': {
-                    'application/json': {
-                        'schema': schema_dict
-                    }
-                },
-                'required': True
-            },
-            'responses': {
-                '204': {'$ref': '#/components/responses/204'},
-                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-            }
-        },
-        'patch': {
-            'summary': 'Partially update admin configuration',
-            'description': 'Partially update admin configuration',
-            'tags': ['admin'],
-            'operationId': 'patchAdminConfig',
-            'requestBody': {
-                'description': 'Updates admin configuration',
-                'content': {
-                    'application/json': {
-                        'schema': schema_dict
+        }
+        mimetype = tile_extension['format']['mimetype']
+        paths[tiles_data_path]['get']['responses']['200'] = {
+            'description': 'successful operation',
+            'content': {
+                mimetype: {
+                    'schema': {
+                        'type': 'string',
+                        'format': 'binary'
                     }
-                },
-                'required': True
-            },
-            'responses': {
-                '204': {'$ref': '#/components/responses/204'},
-                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
             }
         }
-    }
-    paths['/admin/config/resources'] = {
-        'get': {
-            'summary': 'Get admin configuration resources',
-            'description': 'Get admin configuration resources',
-            'tags': ['admin'],
-            'operationId': 'getAdminConfigResources',
-            'parameters': [
-                {'$ref': '#/components/parameters/f'},
-                {'$ref': '#/components/parameters/lang'}
-            ],
-            'responses': {
-                '200': {
-                    'content': {
-                        'application/json': {
-                            'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+
+    LOGGER.debug('setting up edr endpoints')
+    edr_extension = filter_providers_by_type(
+        collection_def['providers'], 'edr')
+
+    if edr_extension:
+        ep = load_plugin('provider', edr_extension)
+
+        edr_query_endpoints = []
+
+        for qt in [qt for qt in ep.get_query_types() if qt != 'locations']:
+            edr_query_endpoints.append({
+                'path': f'{collection_name_path}/{qt}',
+                'qt': qt,
+                'op_id': f'query{qt.capitalize()}{collection_id.capitalize()}'
+            })
+            if ep.instances:
+                edr_query_endpoints.append({
+                    'path': f'{collection_name_path}/instances/{{instanceId}}/{qt}',  # noqa
+                    'qt': qt,
+                    'op_id': f'query{qt.capitalize()}Instance{collection_id.capitalize()}'  # noqa
+                })
+
+        for eqe in edr_query_endpoints:
+            if eqe['qt'] == 'cube':
+                spatial_parameter = 'bbox'
+            else:
+                spatial_parameter = f"{eqe['qt']}Coords"
+            paths[eqe['path']] = {
+                'get': {
+                    'summary': f"query {collection_def['description']} by {eqe['qt']}",  # noqa
+                    'description': collection_def['description'],
+                    'tags': [collection_id],
+                    'operationId': eqe['op_id'],
+                    'parameters': [
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/{spatial_parameter}.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/parameter-name.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/z.yaml"},
+                        {'$ref': '#/components/parameters/f'}
+                    ],
+                    'responses': {
+                        '200': {
+                            'description': 'Response',
+                            'content': {
+                                'application/prs.coverage+json': {
+                                    'schema': {
+                                        '$ref': f"{OPENAPI_YAML['oaedr']}/schemas/coverageJSON.yaml"  # noqa
+                                    }
+                                }
+                            }
                         }
                     }
                 }
             }
-        },
-        'post': {
-            'summary': 'Create admin configuration resource',
-            'description': 'Create admin configuration resource',
-            'tags': ['admin'],
-            'operationId': 'postAdminConfigResource',
-            'requestBody': {
-                'description': 'Adds resource to configuration',
-                'content': {
-                    'application/json': {
-                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+        if 'locations' in ep.get_query_types():
+            paths[f'{collection_name_path}/locations'] = {
+                'get': {
+                    'summary': f"Get pre-defined locations of {v['description']}",  # noqa
+                    'description': collection_def['description'],
+                    'tags': [collection_id],
+                    'operationId': f'queryLOCATIONS{collection_id.capitalize()}',  # noqa
+                    'parameters': [
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/bbox.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
+                        {'$ref': '#/components/parameters/f'}
+                    ],
+                    'responses': {
+                        '200': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/Features"},  # noqa
+                        '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                        '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
                     }
-                },
-                'required': True
-            },
-            'responses': {
-                '201': {'description': 'Successful creation'},
-                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
+                }
             }
-        },
-    }
-    paths['/admin/config/resources/{resourceId}'] = {
-        'get': {
-            'summary': 'Get admin configuration resource',
-            'description': 'Get admin configuration resource',
-            'tags': ['admin'],
-            'operationId': 'getAdminConfigResource',
-            'parameters': [
-                {'$ref': '#/components/parameters/resourceId'},
-                {'$ref': '#/components/parameters/f'},
-                {'$ref': '#/components/parameters/lang'}
-            ],
-            'responses': {
-                '200': {
-                    'content': {
-                        'application/json': {
-                            'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
+            paths[f'{collection_name_path}/locations/{{locId}}'] = {
+                'get': {
+                    'summary': f"query {collection_defv['description']} by location",  # noqa
+                    'description': collection_def['description'],
+                    'tags': [collection_id],
+                    'operationId': f'queryLOCATIONSBYID{collection_id.capitalize()}',  # noqa
+                    'parameters': [
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/{spatial_parameter}.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/locationId.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/parameter-name.yaml"},  # noqa
+                        {'$ref': f"{OPENAPI_YAML['oaedr']}/parameters/z.yaml"},
+                        {'$ref': '#/components/parameters/f'}
+                    ],
+                    'responses': {
+                        '200': {
+                            'description': 'Response',
+                            'content': {
+                                'application/prs.coverage+json': {
+                                    'schema': {
+                                        '$ref': f"{OPENAPI_YAML['oaedr']}/schemas/coverageJSON.yaml"  # noqa
+                                    }
+                                }
+                            }
                         }
                     }
                 }
             }
-        },
-        'put': {
-            'summary': 'Update admin configuration resource',
-            'description': 'Update admin configuration resource',
-            'tags': ['admin'],
-            'operationId': 'putAdminConfigResource',
-            'parameters': [
-                {'$ref': '#/components/parameters/resourceId'},
-            ],
-            'requestBody': {
-                'description': 'Updates admin configuration resource',
-                'content': {
-                    'application/json': {
-                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
-                    }
-                },
-                'required': True
-            },
-            'responses': {
-                '204': {'$ref': '#/components/responses/204'},
-                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-            }
-        },
-        'patch': {
-            'summary': 'Partially update admin configuration resource',
-            'description': 'Partially update admin configuration resource',
-            'tags': ['admin'],
-            'operationId': 'patchAdminConfigResource',
-            'parameters': [
-                {'$ref': '#/components/parameters/resourceId'},
-            ],
-            'requestBody': {
-                'description': 'Updates admin configuration resource',
-                'content': {
-                    'application/json': {
-                        'schema': schema_dict['properties']['resources']['patternProperties']['^.*$']  # noqa
-                    }
-                },
-                'required': True
-            },
-            'responses': {
-                '204': {'$ref': '#/components/responses/204'},
-                '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
-                '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"}  # noqa
-            }
-        },
-        'delete': {
-            'summary': 'Delete admin configuration resource',
-            'description': 'Delete admin configuration resource',
-            'tags': ['admin'],
-            'operationId': 'deleteAdminConfigResource',
-            'parameters': [
-                {'$ref': '#/components/parameters/resourceId'},
-            ],
-            'responses': {
-                '204': {'$ref': '#/components/responses/204'},
-                '404': {'$ref': f"{OPENAPI_YAML['oapip']}/responses/NotFound.yaml"},  # noqa
-                'default': {'$ref': '#/components/responses/default'}  # noqa
+
+    LOGGER.debug('setting up maps endpoints')
+    map_extension = filter_providers_by_type(
+        collection_def['providers'], 'map')
+
+    if map_extension:
+        mp = load_plugin('provider', map_extension)
+
+        map_f = deepcopy(components['parameters']['f'])
+        map_f['schema']['enum'] = [map_extension['format']['name']]
+        map_f['schema']['default'] = map_extension['format']['name']
+
+        pth = f'/collections/{collection_def}/map'
+        paths[pth] = {
+            'get': {
+                'summary': 'Get map',
+                'description': f"{collection_def['description']} map",
+                'tags': [collection_id],
+                'operationId': 'getMap',
+                'parameters': [
+                    {'$ref': '#/components/parameters/bbox'},
+                    {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"},  # noqa
+                    {
+                        'name': 'width',
+                        'in': 'query',
+                        'description': 'Response image width',
+                        'required': False,
+                        'schema': {
+                            'type': 'integer',
+                        },
+                        'style': 'form',
+                        'explode': False
+                    },
+                    {
+                        'name': 'height',
+                        'in': 'query',
+                        'description': 'Response image height',
+                        'required': False,
+                        'schema': {
+                            'type': 'integer',
+                        },
+                        'style': 'form',
+                        'explode': False
+                    },
+                    {
+                        'name': 'transparent',
+                        'in': 'query',
+                        'description': 'Background transparency of map (default=true).',  # noqa
+                        'required': False,
+                        'schema': {
+                            'type': 'boolean',
+                            'default': True,
+                        },
+                        'style': 'form',
+                        'explode': False
+                    },
+                    {'$ref': '#/components/parameters/bbox-crs-epsg'},
+                    map_f
+                ],
+                'responses': {
+                    '200': {
+                        'description': 'Response',
+                        'content': {
+                            'application/json': {}
+                        }
+                    },
+                    '400': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/InvalidParameter"},  # noqa
+                    '500': {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/responses/ServerError"},  # noqa
+                }
             }
         }
-    }
+        if mp.time_field is not None:
+            paths[pth]['get']['parameters'].append(
+                {'$ref': f"{OPENAPI_YAML['oapif-1']}#/components/parameters/datetime"})  # noqa
 
-    return paths
+    return tags, paths
 
 
-def get_oas(cfg, version='3.0'):
+def get_oas(cfg: dict, fail_on_invalid_collection: bool = True,
+            version='3.0') -> dict:
     """
     Stub to generate OpenAPI Document
 
-    :param cfg: configuration object
+    :param cfg: `dict` configuration
+    :param fail_on_invalid_collection: `bool` of whether to fail on an
+                                       invalid collection
     :param version: version of OpenAPI (default 3.0)
 
-    :returns: OpenAPI definition YAML dict
+    :returns: `dict` of OpenAPI definition
     """
 
     if version == '3.0':
-        return get_oas_30(cfg)
+        return get_oas_30(
+            cfg, fail_on_invalid_collection=fail_on_invalid_collection)
     else:
         raise RuntimeError('OpenAPI version not supported')
 
 
-def validate_openapi_document(instance_dict):
+def validate_openapi_document(instance_dict: dict) -> bool:
     """
     Validate an OpenAPI document against the OpenAPI schema
 
@@ -1589,27 +1640,37 @@ def validate_openapi_document(instance_dict):
 
 
 def generate_openapi_document(cfg_file: Union[Path, io.TextIOWrapper],
-                              output_format: OAPIFormat):
+                              output_format: OAPIFormat,
+                              fail_on_invalid_collection: bool = True) -> str:
     """
     Generate an OpenAPI document from the configuration file
 
-    :param cfg_file: configuration Path instance
+    :param cfg_file: configuration Path instance (`str` of filepath
+                     or parsed `dict`)
+    :param fail_on_invalid_collection: `bool` of whether to fail on an
+                                       invalid collection
     :param output_format: output format for OpenAPI document
 
-    :returns: content of the OpenAPI document in the output
-              format requested
+    :returns: `str` of the OpenAPI document in the output format requested
     """
+
+    LOGGER.debug(f'Loading configuration {cfg_file}')
+
     if isinstance(cfg_file, Path):
         with cfg_file.open(mode="r") as cf:
             s = yaml_load(cf)
     else:
         s = yaml_load(cfg_file)
+
     pretty_print = s['server'].get('pretty_print', False)
 
+    oas = get_oas(s, fail_on_invalid_collection=fail_on_invalid_collection)
+
     if output_format == 'yaml':
-        content = yaml.safe_dump(get_oas(s), default_flow_style=False)
+        content = yaml.safe_dump(oas, default_flow_style=False)
     else:
-        content = to_json(get_oas(s), pretty=pretty_print)
+        content = to_json(oas, pretty=pretty_print)
+
     return content
 
 
@@ -1640,17 +1701,21 @@ def openapi():
 @click.command()
 @click.pass_context
 @click.argument('config_file', type=click.File(encoding='utf-8'))
+ at click.option('--fail-on-invalid-collection/--no-fail-on-invalid-collection',
+              '-fic', default=True, help='Fail on invalid collection')
 @click.option('--format', '-f', 'format_', type=click.Choice(['json', 'yaml']),
               default='yaml', help='output format (json|yaml)')
 @click.option('--output-file', '-of', type=click.File('w', encoding='utf-8'),
               help='Name of output file')
-def generate(ctx, config_file, output_file, format_='yaml'):
+def generate(ctx, config_file, output_file, format_='yaml',
+             fail_on_invalid_collection=True):
     """Generate OpenAPI Document"""
 
     if config_file is None:
         raise click.ClickException('--config/-c required')
 
-    content = generate_openapi_document(config_file, format_)
+    content = generate_openapi_document(
+        config_file, format_, fail_on_invalid_collection)
 
     if output_file is None:
         click.echo(content)



View it on GitLab: https://salsa.debian.org/debian-gis-team/pygeoapi/-/compare/4e3b3a513fe647bb80307ba0d4049b607cc14153...87acffe3aa5f26845c9f42107bf41cb775af58f6

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/pygeoapi/-/compare/4e3b3a513fe647bb80307ba0d4049b607cc14153...87acffe3aa5f26845c9f42107bf41cb775af58f6
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20240405/e7ee81c7/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list