better-fe-error-handling (#1406)

* update error handling in HttpService to handle non-json responses better w/ burnettk

* fixed cypress tests

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-04-18 18:11:44 +00:00 committed by GitHub
parent 6643db9f2f
commit 91e988ff11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 33 additions and 21 deletions

View File

@ -1,3 +1,4 @@
/* eslint-disable max-classes-per-file */
import { BACKEND_BASE_URL } from '../config';
import { objectIsEmpty } from '../helpers';
import UserService from './UserService';
@ -36,6 +37,13 @@ export class UnauthenticatedError extends Error {
}
}
export class UnexpectedResponseError extends Error {
constructor(message: string) {
super(message);
this.name = 'UnexpectedResponseError';
}
}
const makeCallToBackend = ({
path,
successCallback,
@ -74,47 +82,51 @@ backendCallProps) => {
const updatedPath = path.replace(/^\/v1\.0/, '');
let isSuccessful = true;
// this fancy 403 handling is like this because we want to get the response body.
// otherwise, we would just throw an exception.
let is403 = false;
fetch(`${BACKEND_BASE_URL}${updatedPath}`, httpArgs)
.then((response) => {
if (response.status === 401) {
throw new UnauthenticatedError('You must be authenticated to do this.');
} else if (response.status === 403) {
is403 = true;
isSuccessful = false;
} else if (!response.ok) {
isSuccessful = false;
}
return response.json();
return response.text().then((result: any) => {
return { response, text: result };
});
})
.then((result: any) => {
if (isSuccessful) {
successCallback(result);
} else if (is403) {
let jsonResult = null;
try {
jsonResult = JSON.parse(result.text);
} catch (error) {
if (error instanceof SyntaxError) {
throw new UnexpectedResponseError(
`Received unexpected response from server. Status: ${result.response.status}: ${result.response.statusText}. Body: ${result.text}`
);
}
throw error;
}
if (result.response.status === 403) {
if (onUnauthorized) {
onUnauthorized(result);
onUnauthorized(jsonResult);
} else if (UserService.isPublicUser()) {
window.location.href = '/public/sign-out';
} else {
// Hopefully we can make this service a hook and use the error message context directly
// eslint-disable-next-line no-alert
alert(result.message);
}
} else {
let message = 'A server error occurred.';
if (result.message) {
message = result.message;
alert(jsonResult.message);
}
} else if (!result.response.ok) {
if (failureCallback) {
failureCallback(result);
failureCallback(jsonResult);
} else {
let message = 'A server error occurred.';
if (jsonResult.message) {
message = jsonResult.message;
}
console.error(message);
// eslint-disable-next-line no-alert
alert(message);
}
} else {
successCallback(jsonResult);
}
})
.catch((error) => {