Skip to content

Commit

Permalink
Improve profile code API error handling
Browse files Browse the repository at this point in the history
This commit ensures the profile code API client is properly checking for
and handling errors for both profile creation and import API calls.

Previously error handling was only done for profile exports and it
wasn't handling some edge cases properly (apparently Axios does not
always throw an error but instead returns it, this can occur at least if
CORS checks fail).

Now the same error handling is used for both API calls and that error
handling has been adjusted to account for the edge case mentioned
earlier. In practice this means users should see somewhat more legible
error messages for common failures such as 404 HTTP status codes as
opposed to an arbitrary 'Cannot read properties of undefined'.
  • Loading branch information
MythicManiac committed Jan 25, 2024
1 parent 66ac202 commit 983723b
Showing 1 changed file with 46 additions and 31 deletions.
77 changes: 46 additions & 31 deletions src/r2mm/profiles/ProfilesClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,60 @@ const getProfileUrl = (profileImportCode: string): string => {
return `https://thunderstore.io/api/experimental/legacyprofile/get/${profileImportCode}/`;
}

async function createProfile(payload: string): Promise<AxiosResponse<{ key: string }>> {
try {
return await Axios.post(
"https://thunderstore.io/api/experimental/legacyprofile/create/",
payload,
{
headers: { 'Content-Type': 'application/octet-stream' }
}
);
} catch (e: any) {
if (Axios.isAxiosError(e) && e.response) {
if (e.response.status == 429) {
let message = e.message;
try {
message = e.response.data.detail || e.message;
} catch {
}
throw new R2Error(
"Too many exports in a short period of time",
message,
"Wait for a minute and try again"
);
} else {
throw new R2Error(
"Failed to upload profile",
e.message,
`${e.response.status}`
);
function formatApiError<T>(e: T, genericTitle: string): R2Error | T {
if (Axios.isAxiosError(e) && e.response) {
if (e.response.status == 429) {
let message = e.message;
try {
message = e.response.data.detail || e.message;
} catch {
}
return new R2Error(
"Too many attempts in a short period of time",
message,
"You were rate limited by the server, wait for a while and try again."
);
} else {
return new R2Error(
genericTitle,
e.message,
`${e.response.status}`
);
}
}
return e;
}

async function handleApiErrors<I, J>(
apiCall: Promise<AxiosResponse<I, J>>,
errorTitle: string,
): Promise<AxiosResponse<I, J>> {
try {
const response = await apiCall;
if (Axios.isAxiosError(response)) {
throw response;
}
throw e;
return response;
} catch (e: any) {
throw formatApiError(e, errorTitle);
}
}

async function getProfile(profileImportCode: string): Promise<AxiosResponse<string>> {
function createProfile(payload: string): Promise<AxiosResponse<{ key: string }>> {
return handleApiErrors(Axios.post(
"https://thunderstore.io/api/experimental/legacyprofile/create/",
payload,
{
headers: { 'Content-Type': 'application/octet-stream' }
}
), "Failed to upload profile");
}

function getProfile(profileImportCode: string): Promise<AxiosResponse<string>> {
const url = CdnProvider.addCdnQueryParameter(
getProfileUrl(profileImportCode)
);
return await Axios.get(url);
return handleApiErrors(Axios.get(url), "Failed to download profile");
}

export const ProfileApiClient = {
Expand Down

0 comments on commit 983723b

Please sign in to comment.