Categories
interview

Group API calls with callbacks (asynchronous)

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)
     }
   }

 async callApi() {
     if (this.queue.length) {
       let keys = '';
       const keyMap = {};
       while (this.queue.length) {
         const [key, cb] = this.queue.shift();
         keys = keys === '' ? key : keys + ',' + key;
         (keyMap[key] || (keyMap[key] = [])).push(cb);
       }
       try {
         const response = await fetch(this.url + keys);
         if (!response.ok) {
           throw 'Status: ' + response.status;
         }
         const data = await response.json();
         // testing for
         data[data.args.key] = 12;
         for (const [key, val] of Object.entries(data)) {
           keyMap[key] && keyMap[key].forEach(cb => cb(val));
         }
       } catch (e) {
         throw e;
       }
       this.callApi();
     } else {
       this.blocked = false;
     }
   }

 }

 /* Test case */
 const api = new Api('https://httpbin.org/get', 20)
 const test = (x) => console.log(x);
 api.getkey('foo', test)

Demo