From 38c9d0c82a6300550fc0afd2d5903287c56a8c37 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 21 Aug 2023 16:48:17 +0200 Subject: [PATCH] refactor: add response data generic type (#4567) * remove unnecessary type * remove unnecessary type * data should always be returned * added datatype generic * renamed EndpointData to Endpoint * replaced two defaults with one * rename type * removed logs * renamed generic --- frontend/src/ts/ape/adapters/axios-adapter.ts | 5 +- frontend/src/ts/ape/endpoints/ape-keys.ts | 8 +- frontend/src/ts/ape/endpoints/configs.ts | 4 +- frontend/src/ts/ape/endpoints/leaderboards.ts | 4 +- frontend/src/ts/ape/endpoints/presets.ts | 8 +- frontend/src/ts/ape/endpoints/psas.ts | 2 +- frontend/src/ts/ape/endpoints/public.ts | 4 +- frontend/src/ts/ape/endpoints/quotes.ts | 19 +++-- frontend/src/ts/ape/endpoints/results.ts | 10 ++- frontend/src/ts/ape/endpoints/users.ts | 73 ++++++++++--------- frontend/src/ts/ape/types/ape.d.ts | 11 +-- frontend/src/ts/ape/utils.ts | 22 +++--- frontend/src/ts/db.ts | 2 +- frontend/src/ts/elements/psa.ts | 1 + 14 files changed, 89 insertions(+), 84 deletions(-) diff --git a/frontend/src/ts/ape/adapters/axios-adapter.ts b/frontend/src/ts/ape/adapters/axios-adapter.ts index 8f2e7ed5d..8163af894 100644 --- a/frontend/src/ts/ape/adapters/axios-adapter.ts +++ b/frontend/src/ts/ape/adapters/axios-adapter.ts @@ -40,7 +40,7 @@ function apeifyClientMethod( return async ( endpoint: string, options: Ape.RequestOptions = {} - ): Ape.EndpointData => { + ): Ape.EndpointResponse => { let errorMessage = ""; try { @@ -62,7 +62,7 @@ function apeifyClientMethod( ); } - const { message, data } = response.data as Ape.ApiResponse; + const { message, data } = response.data; return { status: response.status, @@ -87,6 +87,7 @@ function apeifyClientMethod( return { status: 500, message: errorMessage, + data: null, }; }; } diff --git a/frontend/src/ts/ape/endpoints/ape-keys.ts b/frontend/src/ts/ape/endpoints/ape-keys.ts index 4c1f936b1..767ab2db3 100644 --- a/frontend/src/ts/ape/endpoints/ape-keys.ts +++ b/frontend/src/ts/ape/endpoints/ape-keys.ts @@ -5,11 +5,11 @@ export default class ApeKeys { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } - async generate(name: string, enabled: boolean): Ape.EndpointData { + async generate(name: string, enabled: boolean): Ape.EndpointResponse { const payload = { name, enabled }; return await this.httpClient.post(BASE_PATH, { payload }); } @@ -17,12 +17,12 @@ export default class ApeKeys { async update( apeKeyId: string, updates: { name?: string; enabled?: boolean } - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { ...updates }; return await this.httpClient.patch(`${BASE_PATH}/${apeKeyId}`, { payload }); } - async delete(apeKeyId: string): Ape.EndpointData { + async delete(apeKeyId: string): Ape.EndpointResponse { return await this.httpClient.delete(`${BASE_PATH}/${apeKeyId}`); } } diff --git a/frontend/src/ts/ape/endpoints/configs.ts b/frontend/src/ts/ape/endpoints/configs.ts index 82bac636a..39361c5c2 100644 --- a/frontend/src/ts/ape/endpoints/configs.ts +++ b/frontend/src/ts/ape/endpoints/configs.ts @@ -5,11 +5,11 @@ export default class Configs { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } - async save(config: MonkeyTypes.Config): Ape.EndpointData { + async save(config: MonkeyTypes.Config): Ape.EndpointResponse { return await this.httpClient.patch(BASE_PATH, { payload: { config } }); } } diff --git a/frontend/src/ts/ape/endpoints/leaderboards.ts b/frontend/src/ts/ape/endpoints/leaderboards.ts index 8071ef5a5..1fa7ad583 100644 --- a/frontend/src/ts/ape/endpoints/leaderboards.ts +++ b/frontend/src/ts/ape/endpoints/leaderboards.ts @@ -18,7 +18,7 @@ export default class Leaderboards { this.httpClient = httpClient; } - async get(query: LeadeboardQueryWithPagination): Ape.EndpointData { + async get(query: LeadeboardQueryWithPagination): Ape.EndpointResponse { const { language, mode, @@ -44,7 +44,7 @@ export default class Leaderboards { return await this.httpClient.get(endpointPath, { searchQuery }); } - async getRank(query: LeaderboardQuery): Ape.EndpointData { + async getRank(query: LeaderboardQuery): Ape.EndpointResponse { const { language, mode, mode2, isDaily, daysBefore } = query; const includeDaysBefore = isDaily && daysBefore; diff --git a/frontend/src/ts/ape/endpoints/presets.ts b/frontend/src/ts/ape/endpoints/presets.ts index cfefb5c91..6afe64156 100644 --- a/frontend/src/ts/ape/endpoints/presets.ts +++ b/frontend/src/ts/ape/endpoints/presets.ts @@ -5,14 +5,14 @@ export default class Presets { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } async add( presetName: string, configChanges: MonkeyTypes.ConfigChanges - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { name: presetName, config: configChanges, @@ -25,7 +25,7 @@ export default class Presets { presetId: string, presetName: string, configChanges: MonkeyTypes.ConfigChanges - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { _id: presetId, name: presetName, @@ -35,7 +35,7 @@ export default class Presets { return await this.httpClient.patch(BASE_PATH, { payload }); } - async delete(presetId: string): Ape.EndpointData { + async delete(presetId: string): Ape.EndpointResponse { return await this.httpClient.delete(`${BASE_PATH}/${presetId}`); } } diff --git a/frontend/src/ts/ape/endpoints/psas.ts b/frontend/src/ts/ape/endpoints/psas.ts index c97706fa2..1dffc1560 100644 --- a/frontend/src/ts/ape/endpoints/psas.ts +++ b/frontend/src/ts/ape/endpoints/psas.ts @@ -5,7 +5,7 @@ export default class Psas { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } } diff --git a/frontend/src/ts/ape/endpoints/public.ts b/frontend/src/ts/ape/endpoints/public.ts index e20ec858e..e9fcb5f57 100644 --- a/frontend/src/ts/ape/endpoints/public.ts +++ b/frontend/src/ts/ape/endpoints/public.ts @@ -11,13 +11,13 @@ export default class Public { this.httpClient = httpClient; } - async getSpeedHistogram(searchQuery: SpeedStatsQuery): Ape.EndpointData { + async getSpeedHistogram(searchQuery: SpeedStatsQuery): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/speedHistogram`, { searchQuery, }); } - async getTypingStats(): Ape.EndpointData { + async getTypingStats(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/typingStats`); } } diff --git a/frontend/src/ts/ape/endpoints/quotes.ts b/frontend/src/ts/ape/endpoints/quotes.ts index aac9cdc4e..72362a5e4 100644 --- a/frontend/src/ts/ape/endpoints/quotes.ts +++ b/frontend/src/ts/ape/endpoints/quotes.ts @@ -5,11 +5,11 @@ export default class Quotes { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } - async isSubmissionEnabled(): Ape.EndpointData { + async isSubmissionEnabled(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/isSubmissionEnabled`); } @@ -18,7 +18,7 @@ export default class Quotes { source: string, language: string, captcha: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { text, source, @@ -33,7 +33,7 @@ export default class Quotes { quoteSubmissionId: string, editText?: string, editSource?: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { quoteId: quoteSubmissionId, editText, @@ -43,13 +43,13 @@ export default class Quotes { return await this.httpClient.post(`${BASE_PATH}/approve`, { payload }); } - async rejectSubmission(quoteSubmissionId: string): Ape.EndpointData { + async rejectSubmission(quoteSubmissionId: string): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/reject`, { payload: { quoteId: quoteSubmissionId }, }); } - async getRating(quote: MonkeyTypes.Quote): Ape.EndpointData { + async getRating(quote: MonkeyTypes.Quote): Ape.EndpointResponse { const searchQuery = { quoteId: quote.id, language: quote.language, @@ -58,7 +58,10 @@ export default class Quotes { return await this.httpClient.get(`${BASE_PATH}/rating`, { searchQuery }); } - async addRating(quote: MonkeyTypes.Quote, rating: number): Ape.EndpointData { + async addRating( + quote: MonkeyTypes.Quote, + rating: number + ): Ape.EndpointResponse { const payload = { quoteId: quote.id, rating, @@ -74,7 +77,7 @@ export default class Quotes { reason: string, comment: string, captcha: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { quoteId, quoteLanguage, diff --git a/frontend/src/ts/ape/endpoints/results.ts b/frontend/src/ts/ape/endpoints/results.ts index 246f8a4c2..eb3dc5a91 100644 --- a/frontend/src/ts/ape/endpoints/results.ts +++ b/frontend/src/ts/ape/endpoints/results.ts @@ -5,23 +5,25 @@ export default class Results { this.httpClient = httpClient; } - async get(): Ape.EndpointData { + async get(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } - async save(result: MonkeyTypes.Result): Ape.EndpointData { + async save( + result: MonkeyTypes.Result + ): Ape.EndpointResponse { return await this.httpClient.post(BASE_PATH, { payload: { result }, }); } - async updateTags(resultId: string, tagIds: string[]): Ape.EndpointData { + async updateTags(resultId: string, tagIds: string[]): Ape.EndpointResponse { return await this.httpClient.patch(`${BASE_PATH}/tags`, { payload: { resultId, tagIds }, }); } - async deleteAll(): Ape.EndpointData { + async deleteAll(): Ape.EndpointResponse { return await this.httpClient.delete(BASE_PATH); } } diff --git a/frontend/src/ts/ape/endpoints/users.ts b/frontend/src/ts/ape/endpoints/users.ts index a92c357cf..c5a0b9732 100644 --- a/frontend/src/ts/ape/endpoints/users.ts +++ b/frontend/src/ts/ape/endpoints/users.ts @@ -5,7 +5,7 @@ export default class Users { this.httpClient = httpClient; } - async getData(): Ape.EndpointData { + async getData(): Ape.EndpointResponse { return await this.httpClient.get(BASE_PATH); } @@ -14,7 +14,7 @@ export default class Users { captcha: string, email?: string, uid?: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { email, name, @@ -25,23 +25,23 @@ export default class Users { return await this.httpClient.post(`${BASE_PATH}/signup`, { payload }); } - async getNameAvailability(name: string): Ape.EndpointData { + async getNameAvailability(name: string): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/checkName/${name}`); } - async delete(): Ape.EndpointData { + async delete(): Ape.EndpointResponse { return await this.httpClient.delete(BASE_PATH); } - async reset(): Ape.EndpointData { + async reset(): Ape.EndpointResponse { return await this.httpClient.patch(`${BASE_PATH}/reset`); } - async optOutOfLeaderboards(): Ape.EndpointData { + async optOutOfLeaderboards(): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/optOutOfLeaderboards`); } - async updateName(name: string): Ape.EndpointData { + async updateName(name: string): Ape.EndpointResponse { return await this.httpClient.patch(`${BASE_PATH}/name`, { payload: { name }, }); @@ -52,7 +52,7 @@ export default class Users { mode2: MonkeyTypes.Mode2, language: string, rank: number - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { mode, mode2, @@ -65,7 +65,10 @@ export default class Users { }); } - async updateEmail(newEmail: string, previousEmail: string): Ape.EndpointData { + async updateEmail( + newEmail: string, + previousEmail: string + ): Ape.EndpointResponse { const payload = { newEmail, previousEmail, @@ -74,35 +77,35 @@ export default class Users { return await this.httpClient.patch(`${BASE_PATH}/email`, { payload }); } - async deletePersonalBests(): Ape.EndpointData { + async deletePersonalBests(): Ape.EndpointResponse { return await this.httpClient.delete(`${BASE_PATH}/personalBests`); } async addResultFilterPreset( filter: MonkeyTypes.ResultFilters - ): Ape.EndpointData { + ): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/resultFilterPresets`, { payload: filter, }); } - async removeResultFilterPreset(id: string): Ape.EndpointData { + async removeResultFilterPreset(id: string): Ape.EndpointResponse { return await this.httpClient.delete( `${BASE_PATH}/resultFilterPresets/${id}` ); } - async getTags(): Ape.EndpointData { + async getTags(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/tags`); } - async createTag(tagName: string): Ape.EndpointData { + async createTag(tagName: string): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/tags`, { payload: { tagName }, }); } - async editTag(tagId: string, newName: string): Ape.EndpointData { + async editTag(tagId: string, newName: string): Ape.EndpointResponse { const payload = { tagId, newName, @@ -111,24 +114,24 @@ export default class Users { return await this.httpClient.patch(`${BASE_PATH}/tags`, { payload }); } - async deleteTag(tagId: string): Ape.EndpointData { + async deleteTag(tagId: string): Ape.EndpointResponse { return await this.httpClient.delete(`${BASE_PATH}/tags/${tagId}`); } - async deleteTagPersonalBest(tagId: string): Ape.EndpointData { + async deleteTagPersonalBest(tagId: string): Ape.EndpointResponse { return await this.httpClient.delete( `${BASE_PATH}/tags/${tagId}/personalBest` ); } - async getCustomThemes(): Ape.EndpointData { + async getCustomThemes(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/customThemes`); } async editCustomTheme( themeId: string, newTheme: Partial - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { themeId: themeId, theme: { @@ -141,7 +144,7 @@ export default class Users { }); } - async deleteCustomTheme(themeId: string): Ape.EndpointData { + async deleteCustomTheme(themeId: string): Ape.EndpointResponse { const payload = { themeId: themeId, }; @@ -152,12 +155,12 @@ export default class Users { async addCustomTheme( newTheme: Partial - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { name: newTheme.name, colors: newTheme.colors }; return await this.httpClient.post(`${BASE_PATH}/customThemes`, { payload }); } - async getOauthLink(): Ape.EndpointData { + async getOauthLink(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/discord/oauth`); } @@ -165,20 +168,20 @@ export default class Users { tokenType: string, accessToken: string, state: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/discord/link`, { payload: { tokenType, accessToken, state }, }); } - async unlinkDiscord(): Ape.EndpointData { + async unlinkDiscord(): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/discord/unlink`); } async addQuoteToFavorites( language: string, quoteId: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { language, quoteId }; return await this.httpClient.post(`${BASE_PATH}/favoriteQuotes`, { payload, @@ -188,25 +191,25 @@ export default class Users { async removeQuoteFromFavorites( language: string, quoteId: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { language, quoteId }; return await this.httpClient.delete(`${BASE_PATH}/favoriteQuotes`, { payload, }); } - async getProfileByUid(uid: string): Promise { + async getProfileByUid(uid: string): Promise { return await this.httpClient.get(`${BASE_PATH}/${uid}/profile?isUid`); } - async getProfileByName(name: string): Promise { + async getProfileByName(name: string): Promise { return await this.httpClient.get(`${BASE_PATH}/${name}/profile`); } async updateProfile( profileUpdates: Partial, selectedBadgeId?: number - ): Promise { + ): Promise { return await this.httpClient.patch(`${BASE_PATH}/profile`, { payload: { ...profileUpdates, @@ -215,14 +218,14 @@ export default class Users { }); } - async getInbox(): Promise { + async getInbox(): Promise { return await this.httpClient.get(`${BASE_PATH}/inbox`); } async updateInbox(options: { mailIdsToDelete?: string[]; mailIdsToMarkRead?: string[]; - }): Promise { + }): Promise { const payload = { mailIdsToDelete: options.mailIdsToDelete, mailIdsToMarkRead: options.mailIdsToMarkRead, @@ -235,7 +238,7 @@ export default class Users { reason: string, comment: string, captcha: string - ): Ape.EndpointData { + ): Ape.EndpointResponse { const payload = { uid, reason, @@ -246,17 +249,17 @@ export default class Users { return await this.httpClient.post(`${BASE_PATH}/report`, { payload }); } - async verificationEmail(): Ape.EndpointData { + async verificationEmail(): Ape.EndpointResponse { return await this.httpClient.get(`${BASE_PATH}/verificationEmail`); } - async forgotPasswordEmail(email: string): Ape.EndpointData { + async forgotPasswordEmail(email: string): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/forgotPasswordEmail`, { payload: { email }, }); } - async setStreakHourOffset(hourOffset: number): Ape.EndpointData { + async setStreakHourOffset(hourOffset: number): Ape.EndpointResponse { return await this.httpClient.post(`${BASE_PATH}/setStreakHourOffset`, { payload: { hourOffset }, }); diff --git a/frontend/src/ts/ape/types/ape.d.ts b/frontend/src/ts/ape/types/ape.d.ts index 3509ecb21..393b5be06 100644 --- a/frontend/src/ts/ape/types/ape.d.ts +++ b/frontend/src/ts/ape/types/ape.d.ts @@ -5,13 +5,13 @@ declare namespace Ape { payload?: any; } - interface HttpClientResponse { + interface HttpClientResponse { status: number; message: string; - data?: any; + data: Data | null; } - type EndpointData = Promise; + type EndpointResponse = Promise>; type HttpClientMethod = ( endpoint: string, @@ -27,9 +27,4 @@ declare namespace Ape { } type HttpMethodTypes = keyof HttpClient; - - interface ApiResponse { - message: string; - data: any | null; - } } diff --git a/frontend/src/ts/ape/utils.ts b/frontend/src/ts/ape/utils.ts index f0bd37eb8..81cf413df 100644 --- a/frontend/src/ts/ape/utils.ts +++ b/frontend/src/ts/ape/utils.ts @@ -1,10 +1,10 @@ -type ShouldRetryCallback = ( +type ShouldRetryCallback = ( statusCode: number, - response?: Ape.HttpClientResponse + response?: Ape.HttpClientResponse ) => boolean; -interface RetryOptions { - shouldRetry?: ShouldRetryCallback; +interface RetryOptions { + shouldRetry?: ShouldRetryCallback; retryAttempts?: number; retryDelayMs?: number; } @@ -19,14 +19,14 @@ const DEFAULT_RETRY_OPTIONS: Required = { retryDelayMs: 3000, }; -export async function withRetry( - fn: () => Ape.EndpointData, - opts?: RetryOptions -): Ape.EndpointData { +export async function withRetry( + fn: () => Ape.EndpointResponse, + opts?: RetryOptions +): Ape.EndpointResponse { const retry = async ( - previousData: Ape.HttpClientResponse, - completeOpts: Required - ): Promise => { + previousData: Ape.HttpClientResponse, + completeOpts: Required> + ): Promise> => { const { retryAttempts, shouldRetry, retryDelayMs } = completeOpts; if (retryAttempts <= 0 || !shouldRetry(previousData.status, previousData)) { diff --git a/frontend/src/ts/db.ts b/frontend/src/ts/db.ts index 37048757b..12ac7ecf2 100644 --- a/frontend/src/ts/db.ts +++ b/frontend/src/ts/db.ts @@ -91,7 +91,7 @@ export async function initSnapshot(): Promise< configResponse, tagsResponse, presetsResponse, - ].map((response: Ape.HttpClientResponse) => response.data); + ].map((response) => response.data); snap.name = userData.name; snap.personalBests = userData.personalBests; diff --git a/frontend/src/ts/elements/psa.ts b/frontend/src/ts/elements/psa.ts index d9c7f0b9b..eacb26157 100644 --- a/frontend/src/ts/elements/psa.ts +++ b/frontend/src/ts/elements/psa.ts @@ -20,6 +20,7 @@ function setMemory(id: string): void { async function getLatest(): Promise { const response = await Ape.psas.get(); + if (response.status === 500) { if (isLocalhost()) { Notifications.addBanner(