pink-bears
Version:
Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications
168 lines • 4.82 kB
JavaScript
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;