diff --git a/api/views/datasources.py b/api/views/datasources.py index 1804a6da47d915b5b9184f678b49a45b961f300a..793acbb21ba9fa9a3a3f41ec939a12b416f96c6e 100644 --- a/api/views/datasources.py +++ b/api/views/datasources.py @@ -14,6 +14,7 @@ from requests.exceptions import HTTPError from .. import permissions from datasources import models, serializers +from datasources.connectors.base import DatasetNotFoundError from provenance import models as prov_models @@ -104,7 +105,8 @@ class DataSourceApiViewset(viewsets.ReadOnlyModelViewSet): """ Attempt to pass a response from the data connector using the function `map_response`. - If the data connectors raises an error (AttributeError or NotImplementedError) then return an error response. + If the data connectors raises an error (AttributeError, DatasetNotFoundError or NotImplementedError) + then return an error response. :param map_response: Function to get response from data connector - must return HttpResponse :param error_message: Error message in case data connector raises an error @@ -120,7 +122,15 @@ class DataSourceApiViewset(viewsets.ReadOnlyModelViewSet): params = None if dataset is not None: - data_connector = data_connector[dataset] + try: + data_connector = data_connector[dataset] + + except DatasetNotFoundError: + data = { + 'status': 'error', + 'message': 'Dataset does not exist within this data source' + } + return response.Response(data, status=404) # Record this action in PROV if not instance.prov_exempt: diff --git a/datasources/connectors/base.py b/datasources/connectors/base.py index 9ce115877702be2cacf0ee82f654472a61718e6a..19e6b872c879dc6cc1987e35edafacd9631fd556 100644 --- a/datasources/connectors/base.py +++ b/datasources/connectors/base.py @@ -16,6 +16,13 @@ import requests.auth from core import plugin +class DatasetNotFoundError(Exception): + """ + Exception raised when a requested dataset cannot be found within a data source. + """ + pass + + @enum.unique class AuthMethod(enum.IntEnum): """ @@ -232,6 +239,13 @@ class DataCatalogueConnector(BaseDataConnector, collections_abc.Mapping): @abc.abstractmethod def __getitem__(self, item: str) -> BaseDataConnector: + """ + Get a data connector for a single dataset within this catalogue. + + :param item: Dataset id + :return: Data connector for dataset + :raises DatasetNotFoundError: Requested dataset cannot be found + """ raise NotImplementedError def __iter__(self): diff --git a/datasources/connectors/hypercat.py b/datasources/connectors/hypercat.py index 33bf26a091caa4fe66407d0001f92715794e0d05..ea8d533e7dbf7ac814f9e2f8723e4969e7c3ab80 100644 --- a/datasources/connectors/hypercat.py +++ b/datasources/connectors/hypercat.py @@ -4,7 +4,7 @@ This module contains data connector classes for retrieving data from HyperCat ca import typing -from .base import BaseDataConnector, DataCatalogueConnector, DataSetConnector +from .base import BaseDataConnector, DataCatalogueConnector, DataSetConnector, DatasetNotFoundError class HyperCat(DataCatalogueConnector): @@ -27,12 +27,18 @@ class HyperCat(DataCatalogueConnector): response = self._get_response(params) - dataset_item = self._get_item_by_key_value( - response['items'], - 'href', - item - ) - metadata = dataset_item['item-metadata'] + try: + dataset_item = self._get_item_by_key_value( + response['items'], + 'href', + item + ) + metadata = dataset_item['item-metadata'] + + except KeyError as e: + raise DatasetNotFoundError( + 'Dataset {0} could not be found'.format(item) + ) from e try: try: diff --git a/docs/source/ref_applications_api.rst b/docs/source/ref_applications_api.rst index 496ab6852b2a0142744a088b6b5011647a098299..eb661316609b68a96d913a8932464b1caa4512e0 100644 --- a/docs/source/ref_applications_api.rst +++ b/docs/source/ref_applications_api.rst @@ -381,7 +381,7 @@ Responses messages: API Endpoints - Catalogues -------------------------- -Data catalogues are a subset of data sources which contain a number of distinct data sets. +Data catalogues are a subset of data sources which contain a number of distinct datasets. -------- @@ -476,7 +476,7 @@ Parameters: - integer * - dataset_id - - The id of the data set within the specific data source, which may be a URI + - The id of the dataset within the specific data source, which may be a URI - string Response class (Status 200): application/json @@ -493,7 +493,7 @@ Responses messages: - Response Type * - 200 - - Data set metadata + - Dataset metadata - Successful - application/json @@ -523,7 +523,7 @@ Responses messages: { "status": "error", - "message": "Data set does not exist within this data source" + "message": "Dataset does not exist within this data source" } - Parameter dataset_id did not refer to a valid dataset within this data source @@ -557,7 +557,7 @@ Parameters: - integer * - dataset_id - - The id of the data set within the specific data source, which may be a URI + - The id of the dataset within the specific data source, which may be a URI - string * - query_string @@ -578,7 +578,7 @@ Responses messages: - Response Type * - 200 - - Data set data + - Dataset data - Successful - application/json @@ -608,7 +608,7 @@ Responses messages: { "status": "error", - "message": "Data set does not exist within this data source" + "message": "Dataset does not exist within this data source" } - Parameter dataset_id did not refer to a valid dataset within this data source