diff --git a/frontend/package.json b/frontend/package.json index 0afaa9ea83..612e723f28 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -82,6 +82,7 @@ "history": "4.10.1", "html-webpack-plugin": "5.5.0", "http-proxy-middleware": "3.0.3", + "http-status-codes": "2.3.0", "i18next": "^21.6.12", "i18next-browser-languagedetector": "^6.1.3", "i18next-http-backend": "^1.3.2", diff --git a/frontend/src/api/ErrorResponseHandlerV2.ts b/frontend/src/api/ErrorResponseHandlerV2.ts new file mode 100644 index 0000000000..cb1f2c7015 --- /dev/null +++ b/frontend/src/api/ErrorResponseHandlerV2.ts @@ -0,0 +1,46 @@ +import { AxiosError } from 'axios'; +import { ErrorV2 } from 'types/api'; +import APIError from 'types/api/error'; + +// reference - https://axios-http.com/docs/handling_errors +export function ErrorResponseHandlerV2(error: AxiosError): never { + const { response, request } = error; + // The request was made and the server responded with a status code + // that falls out of the range of 2xx + if (response) { + throw new APIError({ + httpStatusCode: response.status || 500, + error: { + code: response.data.code, + message: response.data.message, + url: response.data.url, + errors: response.data.errors, + }, + }); + } + // The request was made but no response was received + // `error.request` is an instance of XMLHttpRequest in the browser and an instance of + // http.ClientRequest in node.js + if (request) { + throw new APIError({ + httpStatusCode: error.status || 500, + error: { + code: error.code || error.name, + message: error.message, + url: '', + errors: [], + }, + }); + } + + // Something happened in setting up the request that triggered an Error + throw new APIError({ + httpStatusCode: error.status || 500, + error: { + code: error.name, + message: error.message, + url: '', + errors: [], + }, + }); +} diff --git a/frontend/src/api/login/login.ts b/frontend/src/api/login/login.ts new file mode 100644 index 0000000000..6ca54bd618 --- /dev/null +++ b/frontend/src/api/login/login.ts @@ -0,0 +1,26 @@ +import axios from 'api'; +import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2'; +import { AxiosError } from 'axios'; +import { ErrorV2, SuccessResponseV2 } from 'types/api'; +import { PayloadProps, Props } from 'types/api/user/login'; + +const login = async ( + props: Props, +): Promise> => { + try { + const response = await axios.post(`/login`, { + ...props, + }); + + return { + httpStatusCode: response.status, + data: response.data, + }; + } catch (error) { + ErrorResponseHandlerV2(error as AxiosError); + // this line is never reached but ts isn't detecting the never type properly for the ErrorResponseHandlerV2 + throw error; + } +}; + +export default login; diff --git a/frontend/src/types/api/error.ts b/frontend/src/types/api/error.ts new file mode 100644 index 0000000000..8ad328817e --- /dev/null +++ b/frontend/src/types/api/error.ts @@ -0,0 +1,18 @@ +import { StatusCodes } from 'http-status-codes'; + +import { ErrorResponseV2 } from '.'; + +class APIError extends Error { + error: ErrorResponseV2; + + constructor(error: ErrorResponseV2) { + super(error.error.message); + this.error = error; + } + + getHttpStatusCode(): StatusCodes { + return this.error.httpStatusCode; + } +} + +export default APIError; diff --git a/frontend/src/types/api/index.ts b/frontend/src/types/api/index.ts index b7a0ed57e4..28512bb8d7 100644 --- a/frontend/src/types/api/index.ts +++ b/frontend/src/types/api/index.ts @@ -1,3 +1,4 @@ +import { StatusCodes } from 'http-status-codes'; import { ErrorStatusCode, SuccessStatusCode } from 'types/common'; export type ApiResponse = { data: T }; @@ -17,3 +18,24 @@ export interface SuccessResponse { error: null; params?: P; } + +// Standardize SuccessResponse and Error Response +export interface AdditionalErrors { + message: string; +} + +export interface ErrorV2 { + code: string; + message: string; + url: string; + errors: AdditionalErrors[]; +} +export interface ErrorResponseV2 { + httpStatusCode: StatusCodes; + error: ErrorV2; +} + +export interface SuccessResponseV2 { + httpStatusCode: StatusCodes; + data: T; +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 81f6bc8d80..1a4cfdd4eb 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -10024,6 +10024,11 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" +http-status-codes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.3.0.tgz#987fefb28c69f92a43aecc77feec2866349a8bfc" + integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz"