Description of the issue
When the prod API access key isn't provided to an imap-data-access query, the resulting error message doesn't tell the user that there is a credential issue. Instead, it returns zero files. This is because the production server doesn't return a 401 Unauthorized response when no API key is present in the request headers. Instead, it silently returns an empty result and no exception is raised.
Steps to reproduce the issue
Run the following cli command:
imap-data-access query --instrument glows
This returns the following:
Found [0] matching files in science table
Expected vs Actual behavior
Actual behavior:
If prod key and prod url are both missing
imap-data-access query --instrument glows
Found [0] matching files in science table
If only prod key is missing
prod-url imap-data-access query --instrument glows
Found [0] matching files in science table
If prod key is incorrect
bad-prod-key imap-data-access query --instrument glows
IMAPDataAccessError('403 Forbidden: {"message":"Forbidden"}')
Expected behavior
If no key is provided for prod, then a 401 unauthorized error should be raised
IMAPDataAccessError('401 Unauthorized: {"message":"Unauthorized"}')
Code Snippet (If applicable)
The current error message comes from the _print_query_results_table() function in cli.py
def _print_query_results_table(query_results: list[dict]):
"""Print the query results in a table.
Parameters
----------
query_results : list
A list of dictionaries containing the query results
"""
num_files = len(query_results)
query_table = "science" # default to science so empty list can be printed
print(f"Found [{num_files}] matching files in {query_table} table")
if num_files == 0:
return
When no prod key is provided, the _make_request() function in io.py yields a successful response and doesn't enter the requests.exceptions.HTTPError part of the following code to raise an exception.
try:
with requests.Session() as session:
session.mount("https://", _RETRY_ADAPTER)
response = session.send(request)
response.raise_for_status()
yield response
except requests.exceptions.HTTPError as e:
# e.response.reason captures the error message from the API
error_msg = f"{e.response.status_code} {e.response.reason}: {e.response.text}"
raise IMAPDataAccessError(error_msg) from e
except requests.exceptions.RequestException as e:
# Handle cases where response may not exist (connection errors, timeouts, etc.)
raise IMAPDataAccessError(str(e)) from e
To fix this, the API gateway or backend would need to make the x-api-key header required on the relevant endpoints, so that unauthenticated requests are rejected before they ever reach the database query logic. Once that's done on the server side, the existing HTTPError handling in _make_request would catch the 401 and surface a clear error.
There are ways to catch and raise this issue in the io.py file (such as in _get_base_url() or in query()) but this is less clean. Authentication should be handled by the prod server.
Additional notes, affected areas, and suggested fixes
Fix authentication issue on server side
Description of the issue
When the prod API access key isn't provided to an imap-data-access query, the resulting error message doesn't tell the user that there is a credential issue. Instead, it returns zero files. This is because the production server doesn't return a 401 Unauthorized response when no API key is present in the request headers. Instead, it silently returns an empty result and no exception is raised.
Steps to reproduce the issue
Run the following cli command:
imap-data-access query --instrument glows
This returns the following:
Found [0] matching files in science table
Expected vs Actual behavior
Actual behavior:
If prod key and prod url are both missing
If only prod key is missing
If prod key is incorrect
Expected behavior
If no key is provided for prod, then a 401 unauthorized error should be raised
Code Snippet (If applicable)
The current error message comes from the
_print_query_results_table()function in cli.pyWhen no prod key is provided, the
_make_request()function in io.py yields a successful response and doesn't enter the requests.exceptions.HTTPError part of the following code to raise an exception.To fix this, the API gateway or backend would need to make the x-api-key header required on the relevant endpoints, so that unauthenticated requests are rejected before they ever reach the database query logic. Once that's done on the server side, the existing HTTPError handling in _make_request would catch the 401 and surface a clear error.
There are ways to catch and raise this issue in the io.py file (such as in
_get_base_url()or inquery()) but this is less clean. Authentication should be handled by the prod server.Additional notes, affected areas, and suggested fixes
Fix authentication issue on server side