UNPKG

pink-bears

Version:

Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications

180 lines (155 loc) 4.86 kB
const constants = await require("../constants/index"); const { initHandlers } = require("../appnest-backup/sparrowapps-helper/index"); const { hasExpired } = require("../helpers/index"); const { $Storage, $Fetch } = initHandlers(); const { baseUrl, endPoints, grantType, httpMethods } = constants; class BackendTemplate { constructor(appnestUserId, productId, userId, clientId, clientSecret, redirectUri, IntegrationName) { Object.assign(this, { appnestUserId, productId, userId, clientId, clientSecret, redirectUri, IntegrationName }); } async checkHasFeature(featureName) { try { const feature = await this.makeRequest({ appnestUserId: this.appnestUserId, userId: this.userId, method: httpMethods.GET, endPoint: endPoints.featureEndpoint, queryString: `feature_name=${featureName}`, }); return feature?.data.data.feature_exists; } catch (error) { this.logError('Error while checking feature', error); throw error; } } async makeRequest({ method, endPoint, queryString = null, payload, apiKey, }) { try { let accessToken = apiKey; if (!apiKey) { accessToken = await this.getAccessToken(); } const url = `${baseUrl}${endPoint}${queryString ? `?${queryString}` : ''}`; const apiConfig = { headers: { Authorization: `Bearer ${accessToken}` }, isOAuth: false, maxAttempts: 5, }; this.logApiRequest(method, url, payload); return await this.executeRequest(method, url, payload, apiConfig); } catch (error) { this.logError('Error while making request', error); throw error; } } async getAccessToken() { const storage = await $Storage.getV2(this.userId); let { accessToken, refreshToken, expiresIn } = storage; if (hasExpired(expiresIn)) { const refreshedToken = await this.refreshAccessToken(refreshToken); accessToken = refreshedToken.data.access_token; await $Storage.setV2(this.userId, { ...storage, accessToken, expiresIn: new Date( (Math.floor(Date.now() / 1000) + refreshedToken.data.expires_in) * 1000 ), }); } return accessToken; } async refreshAccessToken(refreshToken) { const refreshPayload = { client_id: this.clientId, client_secret: this.clientSecret, grant_type: grantType.refreshToken, refresh_token: refreshToken, }; return await $Fetch.post( `${baseUrl}${endPoints.tokenEndpoint}`, refreshPayload ); } executeRequest(method, url, payload, apiConfig) { const methodMap = { [httpMethods.GET]: () => $Fetch.get(url, apiConfig), [httpMethods.POST]: () => $Fetch.post(url, payload, apiConfig), [httpMethods.PUT]: () => $Fetch.put(url, payload, apiConfig), [httpMethods.DELETE]: () => $Fetch.delete(url, apiConfig), }; const requestMethod = methodMap[method]; if (!requestMethod) { throw new Error(`Unsupported method: ${method}`); } return requestMethod(); } logApiRequest(method, url, payload) { console.log( `<------------- [${this.IntegrationName}] Api request => ${method} Url => ${url} ${ payload ? `Payload => ${JSON.stringify(payload)}` : '' } ------------->` ); } logError(message, error) { console.error( `[${this.IntegrationName}] ${message} for userId ${this.appnestUserId}`, error ); } async setStorageV2({ key, data }) { try { const userData = (await $Storage.getV2(this.userId)) || {}; userData[key] = data; return await $Storage.setV2(this.userId, { ...userData }); } catch (error) { this.logError('Error while setting storage', error); throw error; } } async getStorageV2({ key }) { try { const userData = (await $Storage.getV2(this.userId)) || {}; return userData[key]; } catch (error) { this.logError('Error while getting storage', error); throw error; } } async getUser() { try { const user = await this.makeRequest({ appnestUserId: this.appnestUserId, method: httpMethods.GET, endPoint: endPoints.usersEndpoint, }); return user?.data.data.filter(user => user.current_user); } catch (error) { this.logError('Error while getting user', error); throw error; } } async exchangeAuthCode(code) { const payload = { grant_type: grantType.authorizationCode, code, redirect_uri: this.redirectUri, client_id: this.clientId, client_secret: this.clientSecret, }; return await $Fetch.post(`${baseUrl}${endPoints.tokenEndpoint}`, payload, {}); } } module.exports = BackendTemplate;