Skip to content

Instantly share code, notes, and snippets.

@piboistudios
Last active December 11, 2018 22:04
Show Gist options
  • Save piboistudios/f10d57df225effa72c28843e3951cf2d to your computer and use it in GitHub Desktop.
Save piboistudios/f10d57df225effa72c28843e3951cf2d to your computer and use it in GitHub Desktop.
[ES6] This snippet of code prevents Axios from spamming a failing API endpoint
const axios = require('axios').default.Axios;
const utils = require('axios/lib/utils');
const buildURL = require('./buildURL');
const endpointData = {}
const objectsMatch = (a, b) => {
const match = true;
for (var key in a) {
var aProp = a[key];
var bProp = b[key];
if (aProp !== bProp) {
match = false;
break;
}
}
return match;
}
const config = {
cooldownTime: 2500,
errorThreshhold: 10,
hitsPerSecond: 10,
startErrorWaitTime: 10,
backOffDegree: 1.25
}
axios.prototype.getUri = function getUri(config) {
// config = mergeConfig(this.defaults, config);
return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
};
axios.prototype.oldRequest = axios.prototype.request;
axios.prototype.request = function (axiosConfig) {
// console.log("Debounced request");
const url = this.getUri(axiosConfig);
if (!endpointData[url]) endpointData[url] = { hitsPastSecond: 0, errors: 0, data: null, errorWait: config.startErrorWaitTime, canRequest: true };
const urlData = endpointData[url];
urlData.hitsPastSecond++;
setTimeout(() => {
urlData.hitsPastSecond--
}, 1000);
// console.log({ endpointData, config, urlData, axiosConfig });
return new Promise((resolve, reject) => {
const canRequest = urlData.hitsPastSecond <= config.hitsPerSecond &&
(urlData.errors <= config.errorThreshhold ||
!objectsMatch(axiosConfig.data, urlData.data));
canRequest = canRequest && urlData.canRequest;
if (canRequest) {
urlData.data = config.data;
this.oldRequest(axiosConfig).then(resolve).catch(err => {
// console.log("Debouncing error", err);
urlData.errors++;
urlData.canRequest = false
setTimeout(() => {
urlData.canRequest = true;
}, urlData.errorWait);
urlData.errorWait = urlData.errorWait ** config.backOffDegree;
reject(err);
});
} else {
setTimeout(() => resolve({ data: null }), config.cooldownTime)
}
});
}
// Regenerate alias methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
axios.prototype[method] = function (url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
axios.prototype[method] = function (url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
'use strict';
var utils = require('axios/lib/utils');
function encode(val) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, '+').
replace(/%5B/gi, '[').
replace(/%5D/gi, ']');
}
/**
* Build a URL by appending params to the end
*
* @param {string} url The base of the url (e.g., http://www.google.com)
* @param {object} [params] The params to be appended
* @returns {string} The formatted url
*/
module.exports = function buildURL(url, params, paramsSerializer) {
/*eslint no-param-reassign:0*/
if (!params) {
return url;
}
var serializedParams;
if (paramsSerializer) {
serializedParams = paramsSerializer(params);
} else if (utils.isURLSearchParams(params)) {
serializedParams = params.toString();
} else {
var parts = [];
utils.forEach(params, function serialize(val, key) {
if (val === null || typeof val === 'undefined') {
return;
}
if (utils.isArray(val)) {
key = key + '[]';
} else {
val = [val];
}
utils.forEach(val, function parseValue(v) {
if (utils.isDate(v)) {
v = v.toISOString();
} else if (utils.isObject(v)) {
v = JSON.stringify(v);
}
parts.push(encode(key) + '=' + encode(v));
});
});
serializedParams = parts.join('&');
}
if (serializedParams) {
var hashmarkIndex = url.indexOf('#');
if (hashmarkIndex !== -1) {
url = url.slice(0, hashmarkIndex);
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
}
return url;
};
@piboistudios
Copy link
Author

This will prototype and 'rebuild' the original AxiosStatic object with debouncing logic injected into the request() method

Usage (in an ES6 environment):
import 'axios-debounced-failure.js'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment