Write a class with a method getKey(key, callback) that invokes an API with the provided key. The method should also invoke a callback with the corresponding value returned by the API . Calls that are made within a given interval should be grouped.
Input:
getKey(v1/get?key=foo , () => console.log(x));
Output:
Let us assume the API returns the following
{foo: 50}
Then the callback is going to be invoked with corresponding value 50
// 50
API call with grouped keys, is used when the the subsequent calls are made within a 20 ms delay for example,
Input:
getKey(v1/get?key=foo , () => console.log(x)); // at t = 0
getKey(v1/get?key=bar , () => console.log(x)); // at t = 10
getKey(v1/get?key=foo , () => console.log(x)); // at t =20
Output:
Let us assume the API (domain/get?key=foo,bar,foo) returns the following
{foo: 50, bar: 100}
Then the callbacks are going to be invoked with the corresponding values 50, 100 and 50.
// 50
// 100
// 50
class Api {
constructor(url, delay) {
this.url = `${url}?key=`;
this.delay = delay;
this.queue = [];
this.blocked = false;
}
getkey = (key, cb) => {
this.queue.push([key, cb]);
if (!this.blocked) {
this.blocked = true;
setTimeout(() => this.callApi(), this.delay);
}
};
callApi = async () => {
if (this.queue.length) {
const keyMap = {};
while (this.queue.length) {
const [key, cb] = this.queue.shift();
(keyMap[key] || (keyMap[key] = [])).push(cb);
}
try {
const response = await fetch(this.url + Object.keys(keyMap).join(','));
if (!response.ok) {
throw 'Status: ' + response.status;
}
const data = await response.json();
console.log(data)
/*
Testing for httpbin response.
const data = {
args: {
key: "foo"
}
};
*/
data[data.args.key] = 12;
for (const [key, val] of Object.entries(data)) {
(keyMap[key] || []).forEach(cb => cb(val));
}
} catch (error) {
throw error;
}
this.callApi();
} else {
this.blocked = false;
}
};
}
/* Test case */
const api = new Api('https://httpbin.org/get', 3000);
const test = (x) => console.log(x);
api.getkey('foo', test);