diff --git a/src/APIHandler.py b/src/APIHandler.py index d8701a9..65c67c3 100644 --- a/src/APIHandler.py +++ b/src/APIHandler.py @@ -4,7 +4,18 @@ import elabapi_python as elabapi class APIHandler: """ - Class to standardize the format of the headers of our http requests. + Class which handles all interactions with the eLabFTW API. + It provides methods to retrieve data from the API and download attachments. + It relies minimally on the elabapi-python library, which is used only for downloading attachments + (since the API doesn't support downloading attachments AFAIK). + + Args: + api_key: A valid API key for the eLabFTW instance where the data is stored, with permissions to access the relevant entries. + eLabFTW's API keys are well documented here: https://doc.elabftw.net/docs/usage/api/. + If you don't have an API key and are uncapable of creating one, contact your eLabFTW administrator. + Or RTFM and create one yourself, it's not that hard. + ELABFTW_API_URL: Complete URL of the eLabFTW instance's root for the API endpoints. + In full caps because it won't (shouldn't) be changed much. """ # TO-DO: remove static url. @@ -20,40 +31,54 @@ class APIHandler: def get_entry_from_elabid(self, elabid, entryType="items"): """ - Method which returns a resource's raw data (as dictionary) from its elabid and entry type. + Returns raw data (as dictionary) from its elabid and entry type. - Entry type can be either "experiments" or "items". + args: + elabid: elabftw internal id of the selected resource. + entryType: Resource type. Anything other than "experiments" or "items" WILL raise an error. """ - # TO-DO: validation and error handling on entryType value. + if entryType not in ["experiments", "items"]: + raise Exception( + "You can only download attachments from experiments or items." + ) + header = self.header response = requests.get( headers=header, url=f"{self.elaburl}/{entryType}/{elabid}", verify=True ) - if response.status_code // 100 in [1, 2, 3]: - entry_data = response.json() - return entry_data - elif response.status_code // 100 == 4: + + # Response is 5xx = server error: + if response.status_code // 100 == 5: + raise ConnectionError( + f"There's a problem on the server. Status code: {response.status_code}." + ) + + # Response is 4xx = client error: + if response.status_code // 100 == 4: match response.status_code: case 401 | 403: + # Forbidden or unauthorized: raise ConnectionError( f"Invalid API key, authentication method or elabid. Check if an item with ID = {elabid} actually exists." ) case 404: + # Lapalissian: raise ConnectionError( f"404: Not Found. This means there's no resource with this elabid (wrong elabid?) on your eLabFTW (wrong endpoint?)." ) case 400: + # I genuinely have no idea: raise ConnectionError( f"400: Bad Request. This means the API endpoint you tried to reach is invalid. Did you tamper with the source code? If not, contact the developer." ) case _: + # For some fucking reason, this is the only error I actually get from the API... raise ConnectionError( f"HTTP request failed with status code: {response.status_code} (NOTE: 4xx means user's fault)." ) - else: - raise ConnectionError( - f"There's a problem on the server. Status code: {response.status_code}." - ) + + entry_data = response.json() + return entry_data def download_attachments_data(self, elabid, entryType="experiments"): """ @@ -123,4 +148,3 @@ class APIHandler: with open(os.path.join(dump_dir, f"exp{elabid}-{file}"), "wb") as f: f.write(raw_data) return -