From 09a6466b11e7116ff70c2c07ffa99c4a2bad7efc Mon Sep 17 00:00:00 2001 From: James Graham <J.Graham@software.ac.uk> Date: Mon, 11 Mar 2019 15:37:28 +0000 Subject: [PATCH] Return 404 response if querying dataset which does not exist in source --- api/views/datasources.py | 14 ++++++++++++-- datasources/connectors/base.py | 14 ++++++++++++++ datasources/connectors/hypercat.py | 20 +++++++++++++------- docs/source/ref_applications_api.rst | 14 +++++++------- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/api/views/datasources.py b/api/views/datasources.py index 1804a6d..793acbb 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 9ce1158..19e6b87 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 33bf26a..ea8d533 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 496ab68..eb66131 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 -- GitLab