From 2f58550f46f6f03ac4b8e2097b621be088847a37 Mon Sep 17 00:00:00 2001 From: Vincent Privat Date: Wed, 29 Jan 2025 14:54:46 +0100 Subject: [PATCH] Configure which OGC APIs are available --- pygeoapi-config.yml | 7 ++ pygeoapi/api/__init__.py | 107 ++++++++++------ pygeoapi/django_/urls.py | 105 +++++++++++----- pygeoapi/django_/views.py | 35 ++++-- pygeoapi/flask_app.py | 174 ++++++++++++++++++--------- pygeoapi/openapi.py | 86 ++++++------- pygeoapi/starlette_app.py | 101 +++++++++++++--- pygeoapi/templates/landing_page.html | 2 + 8 files changed, 422 insertions(+), 195 deletions(-) diff --git a/pygeoapi-config.yml b/pygeoapi-config.yml index b260c76d2..416b8b6d0 100644 --- a/pygeoapi-config.yml +++ b/pygeoapi-config.yml @@ -56,6 +56,13 @@ server: # output_dir: /tmp/ # ogc_schemas_location: /opt/schemas.opengis.net admin: false # enable admin api + coverages: true # enable ogcapi-coverages + edr: true # enable ogcapi-edr + features: true # enable ogcapi-features + maps: true # enable ogcapi-maps + processes: true # enable ogcapi-processes + stac: true # enable ogcapi-stac + tiles: true # enable ogcapi-tiles logging: level: ERROR diff --git a/pygeoapi/api/__init__.py b/pygeoapi/api/__init__.py index 44f01f540..5c85d609d 100644 --- a/pygeoapi/api/__init__.py +++ b/pygeoapi/api/__init__.py @@ -122,7 +122,7 @@ DEFAULT_STORAGE_CRS = DEFAULT_CRS -def all_apis() -> dict: +def all_apis(server_cfg: dict = {}) -> dict: """ Return all supported API modules @@ -131,18 +131,36 @@ def all_apis() -> dict: :returns: `dict` of API provider type, API module """ - from . import (coverages, environmental_data_retrieval, itemtypes, maps, - processes, tiles, stac) - - return { - 'coverage': coverages, - 'edr': environmental_data_retrieval, - 'itemtypes': itemtypes, - 'map': maps, - 'process': processes, - 'tile': tiles, - 'stac': stac - } + apis: dict = {} + + from . import itemtypes + apis['itemtypes'] = itemtypes + + if server_cfg.get('coverages', True): + from . import coverages + apis['coverage'] = coverages + + if server_cfg.get('edr', True): + from . import environmental_data_retrieval + apis['edr'] = environmental_data_retrieval + + if server_cfg.get('maps', True): + from . import maps + apis['map'] = maps + + if server_cfg.get('processes', True): + from . import processes + apis['process'] = processes + + if server_cfg.get('tiles', True): + from . import tiles + apis['tile'] = tiles + + if server_cfg.get('stac', True): + from . import stac + apis['stac'] = stac + + return apis def apply_gzip(headers: dict, content: Union[str, bytes]) -> Union[str, bytes]: @@ -742,6 +760,10 @@ def landing_page(api: API, request.locale) } + processes_enabled = api.config['server'].get('processes', True) + stac_enabled = api.config['server'].get('stac', True) + tiles_enabled = api.config['server'].get('tiles', True) + LOGGER.debug('Creating links') # TODO: put title text in config or translatable files? fcm['links'] = [{ @@ -788,42 +810,48 @@ def landing_page(api: API, 'type': FORMAT_TYPES[F_JSON], 'title': l10n.translate('Collections', request.locale), 'href': api.get_collections_url() - }, { - 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/processes', - 'type': FORMAT_TYPES[F_JSON], - 'title': l10n.translate('Processes', request.locale), - 'href': f"{api.base_url}/processes" - }, { - 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/job-list', - 'type': FORMAT_TYPES[F_JSON], - 'title': l10n.translate('Jobs', request.locale), - 'href': f"{api.base_url}/jobs" - }, { - 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/tiling-schemes', - 'type': FORMAT_TYPES[F_JSON], - 'title': l10n.translate('The list of supported tiling schemes as JSON', request.locale), # noqa - 'href': f"{api.base_url}/TileMatrixSets?f=json" - }, { - 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/tiling-schemes', - 'type': FORMAT_TYPES[F_HTML], - 'title': l10n.translate('The list of supported tiling schemes as HTML', request.locale), # noqa - 'href': f"{api.base_url}/TileMatrixSets?f=html" }] + if processes_enabled: + fcm['links'].extend([{ + 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/processes', + 'type': FORMAT_TYPES[F_JSON], + 'title': l10n.translate('Processes', request.locale), + 'href': f"{api.base_url}/processes" + }, { + 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/job-list', + 'type': FORMAT_TYPES[F_JSON], + 'title': l10n.translate('Jobs', request.locale), + 'href': f"{api.base_url}/jobs" + }]) + if tiles_enabled: + fcm['links'].extend([{ + 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/tiling-schemes', + 'type': FORMAT_TYPES[F_JSON], + 'title': l10n.translate('The list of supported tiling schemes as JSON', request.locale), # noqa + 'href': f"{api.base_url}/TileMatrixSets?f=json" + }, { + 'rel': 'http://www.opengis.net/def/rel/ogc/1.0/tiling-schemes', + 'type': FORMAT_TYPES[F_HTML], + 'title': l10n.translate('The list of supported tiling schemes as HTML', request.locale), # noqa + 'href': f"{api.base_url}/TileMatrixSets?f=html" + }]) + headers = request.get_response_headers(**api.api_headers) if request.format == F_HTML: # render fcm['processes'] = False fcm['stac'] = False fcm['collection'] = False + fcm['tiles'] = tiles_enabled if filter_dict_by_key_value(api.config['resources'], 'type', 'process'): - fcm['processes'] = True + fcm['processes'] = processes_enabled if filter_dict_by_key_value(api.config['resources'], 'type', 'stac-collection'): - fcm['stac'] = True + fcm['stac'] = stac_enabled if filter_dict_by_key_value(api.config['resources'], 'type', 'collection'): @@ -882,14 +910,17 @@ def conformance(api, request: APIRequest) -> Tuple[dict, int, str]: :returns: tuple of headers, status code, content """ - apis_dict = all_apis() + apis_dict = all_apis(api.config['server']) + + processes_enabled = api.config['server'].get('processes', True) conformance_list = CONFORMANCE_CLASSES for key, value in api.config['resources'].items(): if value['type'] == 'process': - conformance_list.extend( - apis_dict['process'].CONFORMANCE_CLASSES) + if processes_enabled: + conformance_list.extend( + apis_dict['process'].CONFORMANCE_CLASSES) else: for provider in value['providers']: if provider['type'] in apis_dict: diff --git a/pygeoapi/django_/urls.py b/pygeoapi/django_/urls.py index 5736b2dea..6f148b0d6 100644 --- a/pygeoapi/django_/urls.py +++ b/pygeoapi/django_/urls.py @@ -58,6 +58,15 @@ from . import views +coverages_enabled = settings.PYGEOAPI_CONFIG['server'].get('coverages', True) +edr_enabled = settings.PYGEOAPI_CONFIG['server'].get('edr', True) +features_enabled = settings.PYGEOAPI_CONFIG['server'].get('features', True) +maps_enabled = settings.PYGEOAPI_CONFIG['server'].get('maps', True) +processes_enabled = settings.PYGEOAPI_CONFIG['server'].get('processes', True) +stac_enabled = settings.PYGEOAPI_CONFIG['server'].get('stac', True) +tiles_enabled = settings.PYGEOAPI_CONFIG['server'].get('tiles', True) +admin_enabled = settings.PYGEOAPI_CONFIG['server'].get('admin', False) + def apply_slash_rule(url: str): """ Strip trailing slashes if the API rules are strict about it. @@ -76,16 +85,6 @@ def apply_slash_rule(url: str): views.conformance, name='conformance' ), - path( - apply_slash_rule('TileMatrixSets/'), - views.tilematrixsets, - name='tilematrixsets' - ), - path( - apply_slash_rule('TileMatrixSets/'), - views.tilematrixsets, - name='tilematrixset' - ), path( apply_slash_rule('collections/'), views.collections, @@ -106,6 +105,9 @@ def apply_slash_rule(url: str): views.collection_queryables, name='collection-queryables', ), +] + +features_urlpatterns = [ path( apply_slash_rule('collections//items/'), views.collection_items, @@ -116,30 +118,21 @@ def apply_slash_rule(url: str): views.collection_item, name='collection-item', ), +] + +if features_enabled: + urlpatterns.extend(features_urlpatterns) + +tiles_urlpatterns = [ path( - apply_slash_rule('collections//coverage/'), - views.collection_coverage, - name='collection-coverage', - ), - path( - 'collections//map', - views.collection_map, - name='collection-map', - ), - path( - 'collections//styles//map', - views.collection_style_map, - name='collection-style-map', - ), - path( - apply_slash_rule('collections//tiles/'), - views.collection_tiles, - name='collection-tiles', + apply_slash_rule('TileMatrixSets/'), + views.tilematrixsets, + name='tilematrixsets' ), path( - 'collections//tiles/', - views.collection_tiles_metadata, - name='collection-tiles-metadata', + apply_slash_rule('TileMatrixSets/'), + views.tilematrixsets, + name='tilematrixset' ), path( 'collections//tiles//metadata', @@ -152,6 +145,39 @@ def apply_slash_rule(url: str): views.collection_item_tiles, name='collection-item-tiles', ), +] + +if tiles_enabled: + urlpatterns.extend(tiles_urlpatterns) + +coverages_urlpatterns = [ + path( + apply_slash_rule('collections//coverage/'), + views.collection_coverage, + name='collection-coverage', + ), +] + +if coverages_enabled: + urlpatterns.extend(coverages_urlpatterns) + +maps_urlpatterns = [ + path( + 'collections//map', + views.collection_map, + name='collection-map', + ), + path( + 'collections//styles//map', + views.collection_style_map, + name='collection-style-map', + ), +] + +if maps_enabled: + urlpatterns.extend(maps_urlpatterns) + +edr_urlpatterns = [ path( 'collections//position', views.get_collection_edr_query, @@ -242,6 +268,12 @@ def apply_slash_rule(url: str): views.get_collection_edr_query, name='collection-edr-corridor', ), +] + +if edr_enabled: + urlpatterns.extend(edr_urlpatterns) + +processes_urlpatterns = [ path(apply_slash_rule('processes/'), views.processes, name='processes'), path('processes/', views.processes, name='process-detail'), path('processes//execution', views.process_execution, @@ -258,6 +290,12 @@ def apply_slash_rule(url: str): views.job_results_resource, name='job-results-resource', ), +] + +if processes_enabled: + urlpatterns.extend(processes_urlpatterns) + +stac_urlpatterns = [ path( apply_slash_rule('stac/'), views.stac_catalog_root, @@ -265,6 +303,9 @@ def apply_slash_rule(url: str): ) ] +if stac_enabled: + urlpatterns.extend(stac_urlpatterns) + url_route_prefix = settings.API_RULES.get_url_prefix('django') if url_route_prefix: # Add a URL prefix to all routes if configured @@ -272,7 +313,7 @@ def apply_slash_rule(url: str): path(url_route_prefix, include(urlpatterns)) ] -if settings.PYGEOAPI_CONFIG['server'].get('admin', False): +if admin_enabled: admin_urlpatterns = [ path( apply_slash_rule('admin/config'), diff --git a/pygeoapi/django_/views.py b/pygeoapi/django_/views.py index 682ef51ce..cce34a299 100644 --- a/pygeoapi/django_/views.py +++ b/pygeoapi/django_/views.py @@ -42,15 +42,36 @@ from pygeoapi.api import API, APIRequest, apply_gzip import pygeoapi.api as core_api -import pygeoapi.api.coverages as coverages_api -import pygeoapi.api.environmental_data_retrieval as edr_api import pygeoapi.api.itemtypes as itemtypes_api -import pygeoapi.api.maps as maps_api -import pygeoapi.api.processes as processes_api -import pygeoapi.api.stac as stac_api -import pygeoapi.api.tiles as tiles_api -if settings.PYGEOAPI_CONFIG['server'].get('admin'): +coverages_enabled = settings.PYGEOAPI_CONFIG['server'].get('coverages', True) +edr_enabled = settings.PYGEOAPI_CONFIG['server'].get('edr', True) +features_enabled = settings.PYGEOAPI_CONFIG['server'].get('features', True) +maps_enabled = settings.PYGEOAPI_CONFIG['server'].get('maps', True) +processes_enabled = settings.PYGEOAPI_CONFIG['server'].get('processes', True) +stac_enabled = settings.PYGEOAPI_CONFIG['server'].get('stac', True) +tiles_enabled = settings.PYGEOAPI_CONFIG['server'].get('tiles', True) +admin_enabled = settings.PYGEOAPI_CONFIG['server'].get('admin', False) + +if coverages_enabled: + import pygeoapi.api.coverages as coverages_api + +if edr_enabled: + import pygeoapi.api.environmental_data_retrieval as edr_api + +if maps_enabled: + import pygeoapi.api.maps as maps_api + +if processes_enabled: + import pygeoapi.api.processes as processes_api + +if stac_enabled: + import pygeoapi.api.stac as stac_api + +if tiles_enabled: + import pygeoapi.api.tiles as tiles_api + +if admin_enabled: import pygeoapi.admin as admin_api diff --git a/pygeoapi/flask_app.py b/pygeoapi/flask_app.py index 744862d4f..7ec4dc066 100644 --- a/pygeoapi/flask_app.py +++ b/pygeoapi/flask_app.py @@ -39,13 +39,7 @@ from pygeoapi.api import API, APIRequest, apply_gzip import pygeoapi.api as core_api -import pygeoapi.api.coverages as coverages_api -import pygeoapi.api.environmental_data_retrieval as edr_api import pygeoapi.api.itemtypes as itemtypes_api -import pygeoapi.api.maps as maps_api -import pygeoapi.api.processes as processes_api -import pygeoapi.api.stac as stac_api -import pygeoapi.api.tiles as tiles_api from pygeoapi.openapi import load_openapi_document from pygeoapi.config import get_config from pygeoapi.util import get_mimetype, get_api_rules @@ -54,12 +48,39 @@ CONFIG = get_config() OPENAPI = load_openapi_document() -API_RULES = get_api_rules(CONFIG) +coverages_enabled = CONFIG['server'].get('coverages', True) +edr_enabled = CONFIG['server'].get('edr', True) +features_enabled = CONFIG['server'].get('features', True) +maps_enabled = CONFIG['server'].get('maps', True) +processes_enabled = CONFIG['server'].get('processes', True) +stac_enabled = CONFIG['server'].get('stac', True) +tiles_enabled = CONFIG['server'].get('tiles', True) +admin_enabled = CONFIG['server'].get('admin', False) + +if coverages_enabled: + import pygeoapi.api.coverages as coverages_api + +if edr_enabled: + import pygeoapi.api.environmental_data_retrieval as edr_api + +if maps_enabled: + import pygeoapi.api.maps as maps_api + +if processes_enabled: + import pygeoapi.api.processes as processes_api -if CONFIG['server'].get('admin'): +if stac_enabled: + import pygeoapi.api.stac as stac_api + +if tiles_enabled: + import pygeoapi.api.tiles as tiles_api + +if admin_enabled: import pygeoapi.admin as admin_api from pygeoapi.admin import Admin +API_RULES = get_api_rules(CONFIG) + STATIC_FOLDER = 'static' if 'templates' in CONFIG['server']: STATIC_FOLDER = CONFIG['server']['templates'].get('static', 'static') @@ -67,12 +88,33 @@ APP = Flask(__name__, static_folder=STATIC_FOLDER, static_url_path='/static') APP.url_map.strict_slashes = API_RULES.strict_slashes -BLUEPRINT = Blueprint( - 'pygeoapi', - __name__, - static_folder=STATIC_FOLDER, - url_prefix=API_RULES.get_url_prefix('flask') -) +url_prefix = API_RULES.get_url_prefix('flask') + +BLUEPRINT = Blueprint('pygeoapi', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +COVERAGES_BLUEPRINT = Blueprint('pygeoapi-coverages', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +EDR_BLUEPRINT = Blueprint('pygeoapi-edr', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +FEATURES_BLUEPRINT = Blueprint('pygeoapi-features', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +MAPS_BLUEPRINT = Blueprint('pygeoapi-maps', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +PROCESSES_BLUEPRINT = Blueprint('pygeoapi-processes', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +STAC_BLUEPRINT = Blueprint('pygeoapi-stac', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) +TILES_BLUEPRINT = Blueprint('pygeoapi-tiles', __name__, + static_folder=STATIC_FOLDER, + url_prefix=url_prefix) + ADMIN_BLUEPRINT = Blueprint('admin', __name__, static_folder=STATIC_FOLDER) # CORS: optionally enable from config. @@ -187,7 +229,7 @@ def conformance(): return execute_from_flask(core_api.conformance, request) -@BLUEPRINT.route('/TileMatrixSets/') +@TILES_BLUEPRINT.route('/TileMatrixSets/') def get_tilematrix_set(tileMatrixSetId=None): """ OGC API TileMatrixSet endpoint @@ -201,7 +243,7 @@ def get_tilematrix_set(tileMatrixSetId=None): tileMatrixSetId) -@BLUEPRINT.route('/TileMatrixSets') +@TILES_BLUEPRINT.route('/TileMatrixSets') def get_tilematrix_sets(): """ OGC API TileMatrixSets endpoint @@ -255,12 +297,12 @@ def collection_queryables(collection_id=None): collection_id) -@BLUEPRINT.route('/collections//items', - methods=['GET', 'POST', 'OPTIONS'], - provide_automatic_options=False) -@BLUEPRINT.route('/collections//items/', - methods=['GET', 'PUT', 'DELETE', 'OPTIONS'], - provide_automatic_options=False) +@FEATURES_BLUEPRINT.route('/collections//items', + methods=['GET', 'POST', 'OPTIONS'], + provide_automatic_options=False) +@FEATURES_BLUEPRINT.route('/collections//items/', # noqa + methods=['GET', 'PUT', 'DELETE', 'OPTIONS'], + provide_automatic_options=False) def collection_items(collection_id, item_id=None): """ OGC API collections items endpoint @@ -309,7 +351,7 @@ def collection_items(collection_id, item_id=None): collection_id, item_id) -@BLUEPRINT.route('/collections//coverage') +@COVERAGES_BLUEPRINT.route('/collections//coverage') def collection_coverage(collection_id): """ OGC API - Coverages coverage endpoint @@ -323,7 +365,7 @@ def collection_coverage(collection_id): collection_id, skip_valid_check=True) -@BLUEPRINT.route('/collections//tiles') +@TILES_BLUEPRINT.route('/collections//tiles') def get_collection_tiles(collection_id=None): """ OGC open api collections tiles access point @@ -337,8 +379,8 @@ def get_collection_tiles(collection_id=None): collection_id) -@BLUEPRINT.route('/collections//tiles/') -@BLUEPRINT.route('/collections//tiles//metadata') # noqa +@TILES_BLUEPRINT.route('/collections//tiles/') # noqa +@TILES_BLUEPRINT.route('/collections//tiles//metadata') # noqa def get_collection_tiles_metadata(collection_id=None, tileMatrixSetId=None): """ OGC open api collection tiles service metadata @@ -354,7 +396,7 @@ def get_collection_tiles_metadata(collection_id=None, tileMatrixSetId=None): skip_valid_check=True) -@BLUEPRINT.route('/collections//tiles/\ +@TILES_BLUEPRINT.route('/collections//tiles/\ ///') def get_collection_tiles_data(collection_id=None, tileMatrixSetId=None, tileMatrix=None, tileRow=None, tileCol=None): @@ -377,8 +419,8 @@ def get_collection_tiles_data(collection_id=None, tileMatrixSetId=None, ) -@BLUEPRINT.route('/collections//map') -@BLUEPRINT.route('/collections//styles//map') +@MAPS_BLUEPRINT.route('/collections//map') +@MAPS_BLUEPRINT.route('/collections//styles//map') def collection_map(collection_id, style_id=None): """ OGC API - Maps map render endpoint @@ -394,8 +436,8 @@ def collection_map(collection_id, style_id=None): ) -@BLUEPRINT.route('/processes') -@BLUEPRINT.route('/processes/') +@PROCESSES_BLUEPRINT.route('/processes') +@PROCESSES_BLUEPRINT.route('/processes/') def get_processes(process_id=None): """ OGC API - Processes description endpoint @@ -409,9 +451,9 @@ def get_processes(process_id=None): process_id) -@BLUEPRINT.route('/jobs') -@BLUEPRINT.route('/jobs/', - methods=['GET', 'DELETE']) +@PROCESSES_BLUEPRINT.route('/jobs') +@PROCESSES_BLUEPRINT.route('/jobs/', + methods=['GET', 'DELETE']) def get_jobs(job_id=None): """ OGC API - Processes jobs endpoint @@ -431,7 +473,8 @@ def get_jobs(job_id=None): return execute_from_flask(processes_api.get_jobs, request, job_id) -@BLUEPRINT.route('/processes//execution', methods=['POST']) +@PROCESSES_BLUEPRINT.route('/processes//execution', + methods=['POST']) def execute_process_jobs(process_id): """ OGC API - Processes execution endpoint @@ -445,8 +488,8 @@ def execute_process_jobs(process_id): process_id) -@BLUEPRINT.route('/jobs//results', - methods=['GET']) +@PROCESSES_BLUEPRINT.route('/jobs//results', + methods=['GET']) def get_job_result(job_id=None): """ OGC API - Processes job result endpoint @@ -459,24 +502,24 @@ def get_job_result(job_id=None): return execute_from_flask(processes_api.get_job_result, request, job_id) -@BLUEPRINT.route('/collections//position') -@BLUEPRINT.route('/collections//area') -@BLUEPRINT.route('/collections//cube') -@BLUEPRINT.route('/collections//radius') -@BLUEPRINT.route('/collections//trajectory') -@BLUEPRINT.route('/collections//corridor') -@BLUEPRINT.route('/collections//locations/') -@BLUEPRINT.route('/collections//locations') -@BLUEPRINT.route('/collections//instances//position') # noqa -@BLUEPRINT.route('/collections//instances//area') # noqa -@BLUEPRINT.route('/collections//instances//cube') # noqa -@BLUEPRINT.route('/collections//instances//radius') # noqa -@BLUEPRINT.route('/collections//instances//trajectory') # noqa -@BLUEPRINT.route('/collections//instances//corridor') # noqa -@BLUEPRINT.route('/collections//instances//locations/') # noqa -@BLUEPRINT.route('/collections//instances//locations') # noqa -@BLUEPRINT.route('/collections//instances/') -@BLUEPRINT.route('/collections//instances') +@EDR_BLUEPRINT.route('/collections//position') +@EDR_BLUEPRINT.route('/collections//area') +@EDR_BLUEPRINT.route('/collections//cube') +@EDR_BLUEPRINT.route('/collections//radius') +@EDR_BLUEPRINT.route('/collections//trajectory') +@EDR_BLUEPRINT.route('/collections//corridor') +@EDR_BLUEPRINT.route('/collections//locations/') # noqa +@EDR_BLUEPRINT.route('/collections//locations') # noqa +@EDR_BLUEPRINT.route('/collections//instances//position') # noqa +@EDR_BLUEPRINT.route('/collections//instances//area') # noqa +@EDR_BLUEPRINT.route('/collections//instances//cube') # noqa +@EDR_BLUEPRINT.route('/collections//instances//radius') # noqa +@EDR_BLUEPRINT.route('/collections//instances//trajectory') # noqa +@EDR_BLUEPRINT.route('/collections//instances//corridor') # noqa +@EDR_BLUEPRINT.route('/collections//instances//locations/') # noqa +@EDR_BLUEPRINT.route('/collections//instances//locations') # noqa +@EDR_BLUEPRINT.route('/collections//instances/') # noqa +@EDR_BLUEPRINT.route('/collections//instances') # noqa def get_collection_edr_query(collection_id, instance_id=None, location_id=None): """ @@ -508,7 +551,7 @@ def get_collection_edr_query(collection_id, instance_id=None, ) -@BLUEPRINT.route('/stac') +@STAC_BLUEPRINT.route('/stac') def stac_catalog_root(): """ STAC root endpoint @@ -519,7 +562,7 @@ def stac_catalog_root(): return execute_from_flask(stac_api.get_stac_root, request) -@BLUEPRINT.route('/stac/') +@STAC_BLUEPRINT.route('/stac/') def stac_catalog_path(path): """ STAC path endpoint @@ -603,7 +646,22 @@ def admin_config_resource(resource_id): APP.register_blueprint(BLUEPRINT) -if CONFIG['server'].get('admin'): +if coverages_enabled: + APP.register_blueprint(COVERAGES_BLUEPRINT) +if edr_enabled: + APP.register_blueprint(EDR_BLUEPRINT) +if features_enabled: + APP.register_blueprint(FEATURES_BLUEPRINT) +if maps_enabled: + APP.register_blueprint(MAPS_BLUEPRINT) +if processes_enabled: + APP.register_blueprint(PROCESSES_BLUEPRINT) +if stac_enabled: + APP.register_blueprint(STAC_BLUEPRINT) +if tiles_enabled: + APP.register_blueprint(TILES_BLUEPRINT) + +if admin_enabled: admin_ = Admin(CONFIG, OPENAPI) APP.register_blueprint(ADMIN_BLUEPRINT) diff --git a/pygeoapi/openapi.py b/pygeoapi/openapi.py index 31adce7c2..f8a39dd26 100644 --- a/pygeoapi/openapi.py +++ b/pygeoapi/openapi.py @@ -443,6 +443,9 @@ def get_oas_30(cfg: dict, fail_on_invalid_collection: bool = True) -> dict: items_f = deepcopy(oas['components']['parameters']['f']) items_f['schema']['enum'].append('csv') + tiles_enabled = cfg['server'].get('tiles', True) + admin_enabled = cfg['server'].get('admin', False) + LOGGER.debug('setting up datasets') for k, v in get_visible_collections(cfg).items(): @@ -484,58 +487,59 @@ def get_oas_30(cfg: dict, fail_on_invalid_collection: bool = True) -> dict: } } - oas['components']['responses'].update({ - 'Tiles': { - 'description': 'Retrieves the tiles description for this collection', # noqa - 'content': { - 'application/json': { - 'schema': { - '$ref': '#/components/schemas/tiles' + if tiles_enabled: + oas['components']['responses'].update({ + 'Tiles': { + 'description': 'Retrieves the tiles description for this collection', # noqa + 'content': { + 'application/json': { + 'schema': { + '$ref': '#/components/schemas/tiles' + } } } } } - } - ) - - oas['components']['schemas'].update({ - 'tilematrixsetlink': { - 'type': 'object', - 'required': ['tileMatrixSet'], - 'properties': { - 'tileMatrixSet': { - 'type': 'string' - }, - 'tileMatrixSetURI': { - 'type': 'string' + ) + + 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 + }, + '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 } - }, - 'links': { - 'type': 'array', - 'items': {'$ref': f"{OPENAPI_YAML['oapit']}#/components/schemas/link"} # noqa } } } - } - ) + ) oas['paths'] = paths - for api_name, api_module in all_apis().items(): + for api_name, api_module in all_apis(cfg['server']).items(): LOGGER.debug(f'Adding OpenAPI definitions for {api_name}') try: @@ -548,7 +552,7 @@ def get_oas_30(cfg: dict, fail_on_invalid_collection: bool = True) -> dict: else: LOGGER.warning(f'Resource not added to OpenAPI: {err}') - if cfg['server'].get('admin', False): + if admin_enabled: schema_dict = get_config_schema() oas['definitions'] = schema_dict['definitions'] LOGGER.debug('Adding admin endpoints') diff --git a/pygeoapi/starlette_app.py b/pygeoapi/starlette_app.py index 984e62302..982d6224d 100644 --- a/pygeoapi/starlette_app.py +++ b/pygeoapi/starlette_app.py @@ -51,13 +51,7 @@ from pygeoapi.api import API, APIRequest, apply_gzip import pygeoapi.api as core_api -import pygeoapi.api.coverages as coverages_api -import pygeoapi.api.environmental_data_retrieval as edr_api import pygeoapi.api.itemtypes as itemtypes_api -import pygeoapi.api.maps as maps_api -import pygeoapi.api.processes as processes_api -import pygeoapi.api.stac as stac_api -import pygeoapi.api.tiles as tiles_api from pygeoapi.openapi import load_openapi_document from pygeoapi.config import get_config from pygeoapi.util import get_api_rules @@ -69,7 +63,34 @@ OPENAPI = load_openapi_document() -if CONFIG['server'].get('admin'): +coverages_enabled = CONFIG['server'].get('coverages', True) +edr_enabled = CONFIG['server'].get('edr', True) +features_enabled = CONFIG['server'].get('features', True) +maps_enabled = CONFIG['server'].get('maps', True) +processes_enabled = CONFIG['server'].get('processes', True) +stac_enabled = CONFIG['server'].get('stac', True) +tiles_enabled = CONFIG['server'].get('tiles', True) +admin_enabled = CONFIG['server'].get('admin', False) + +if coverages_enabled: + import pygeoapi.api.coverages as coverages_api + +if edr_enabled: + import pygeoapi.api.environmental_data_retrieval as edr_api + +if maps_enabled: + import pygeoapi.api.maps as maps_api + +if processes_enabled: + import pygeoapi.api.processes as processes_api + +if stac_enabled: + import pygeoapi.api.stac as stac_api + +if tiles_enabled: + import pygeoapi.api.tiles as tiles_api + +if admin_enabled: import pygeoapi.admin as admin_api from pygeoapi.admin import Admin @@ -649,25 +670,60 @@ async def __call__(self, scope: Scope, Route('/', landing_page), Route('/openapi', openapi), Route('/conformance', conformance), - Route('/TileMatrixSets/{tileMatrixSetId}', get_tilematrix_set), - Route('/TileMatrixSets', get_tilematrix_sets), + Route('/collections', collections), + Route('/collections/{collection_id:path}', collections), Route('/collections/{collection_id:path}/schema', collection_schema), Route('/collections/{collection_id:path}/queryables', collection_queryables), # noqa +] + +features_routes = [ + Route('/collections/{collection_id:path}/items', collection_items, methods=['GET', 'POST', 'OPTIONS']), # noqa + Route('/collections/{collection_id:path}/items/{item_id:path}', collection_items, methods=['GET', 'PUT', 'DELETE', 'OPTIONS']) # noqa +] + +if features_enabled: + api_routes.extend(features_routes) + +tiles_routes = [ + Route('/TileMatrixSets/{tileMatrixSetId}', get_tilematrix_set), + Route('/TileMatrixSets', get_tilematrix_sets), Route('/collections/{collection_id:path}/tiles', get_collection_tiles), Route('/collections/{collection_id:path}/tiles/{tileMatrixSetId}', get_collection_tiles_metadata), # noqa Route('/collections/{collection_id:path}/tiles/{tileMatrixSetId}/metadata', get_collection_tiles_metadata), # noqa - Route('/collections/{collection_id:path}/tiles/{tileMatrixSetId}/{tile_matrix}/{tileRow}/{tileCol}', get_collection_items_tiles), # noqa - Route('/collections/{collection_id:path}/items', collection_items, methods=['GET', 'POST', 'OPTIONS']), # noqa - Route('/collections/{collection_id:path}/items/{item_id:path}', collection_items, methods=['GET', 'PUT', 'DELETE', 'OPTIONS']), # noqa - Route('/collections/{collection_id:path}/coverage', collection_coverage), # noqa + Route('/collections/{collection_id:path}/tiles/{tileMatrixSetId}/{tile_matrix}/{tileRow}/{tileCol}', get_collection_items_tiles) # noqa +] + +if tiles_enabled: + api_routes.extend(tiles_routes) + +coverages_routes = [ + Route('/collections/{collection_id:path}/coverage', collection_coverage) # noqa +] + +if coverages_enabled: + api_routes.extend(coverages_routes) + +maps_routes = [ Route('/collections/{collection_id:path}/map', collection_map), - Route('/collections/{collection_id:path}/styles/{style_id:path}/map', collection_map), # noqa + Route('/collections/{collection_id:path}/styles/{style_id:path}/map', collection_map) # noqa +] + +if maps_enabled: + api_routes.extend(maps_routes) + +processes_routes = [ Route('/processes', get_processes), Route('/processes/{process_id}', get_processes), Route('/jobs', get_jobs), Route('/jobs/{job_id}', get_jobs, methods=['GET', 'DELETE']), Route('/processes/{process_id}/execution', execute_process_jobs, methods=['POST']), # noqa - Route('/jobs/{job_id}/results', get_job_result), + Route('/jobs/{job_id}/results', get_job_result) +] + +if processes_enabled: + api_routes.extend(processes_routes) + +edr_routes = [ Route('/collections/{collection_id:path}/position', get_collection_edr_query), # noqa Route('/collections/{collection_id:path}/area', get_collection_edr_query), Route('/collections/{collection_id:path}/cube', get_collection_edr_query), @@ -685,13 +741,20 @@ async def __call__(self, scope: Scope, Route('/collections/{collection_id:path}/instances/{instance_id}/trajectory', get_collection_edr_query), # noqa Route('/collections/{collection_id:path}/instances/{instance_id}/corridor', get_collection_edr_query), # noqa Route('/collections/{collection_id:path}/instances/{instance_id}/locations', get_collection_edr_query), # noqa - Route('/collections/{collection_id:path}/instances/{instance_id}/locations/{location_id}', get_collection_edr_query), # noqa - Route('/collections', collections), - Route('/collections/{collection_id:path}', collections), + Route('/collections/{collection_id:path}/instances/{instance_id}/locations/{location_id}', get_collection_edr_query) # noqa +] + +if edr_enabled: + api_routes.extend(edr_routes) + +stac_routes = [ Route('/stac', stac_catalog_root), Route('/stac/{path:path}', stac_catalog_path) ] +if stac_enabled: + api_routes.extend(stac_routes) + admin_routes = [ Route('/admin/config', admin_config, methods=['GET', 'PUT', 'PATCH']), Route('/admin/config/resources', admin_config_resources, methods=['GET', 'POST']), # noqa @@ -699,7 +762,7 @@ async def __call__(self, scope: Scope, methods=['GET', 'PUT', 'PATCH', 'DELETE']) ] -if CONFIG['server'].get('admin', False): +if admin_enabled: ADMIN = Admin(CONFIG, OPENAPI) api_routes.extend(admin_routes) diff --git a/pygeoapi/templates/landing_page.html b/pygeoapi/templates/landing_page.html index 147b2a9c6..f0a6baf98 100644 --- a/pygeoapi/templates/landing_page.html +++ b/pygeoapi/templates/landing_page.html @@ -97,12 +97,14 @@

{% trans %}Conformance{% endtrans %}

{% trans %}View the conformance classes of this service{% endtrans %}

+ {% if data['tiles'] %}

{% trans %}Tile Matrix Sets{% endtrans %}

{% trans %}View the Tile Matrix Sets available on this service{% endtrans %}

+ {% endif %}