Throttling Axios Requests
Asked Answered
E

3

14

I'm using axios to make requests to the Deezer API. Unfortunately, with Deezer's API when you request an artist's albums it does not include album tracks. So, I am working around this by requesting the artist's albums and then performing a subsequent axios request for each album. The problem I'm running into is that the API limits requests to 50 per 5 seconds. If an artist has more than 50 albums I usually get a "quota exceeded" error. Is there a way to throttle axios requests to 50 per 5 seconds, specifically when using axios.all?

var axios = require('axios');

function getAlbums(artistID) {
  axios.get(`https://api.deezer.com/artist/${artistID}/albums`)
    .then((albums) => {
      const urls = albums.data.data.map((album) => {
        return axios.get(`https://api.deezer.com/album/${album.id}`)
          .then(albumInfo => albumInfo.data);
      });
      axios.all(urls)
        .then((allAlbums) => {
          console.log(allAlbums);
        });
    }).catch((err) => {
      console.log(err);
    });
}

getAlbums(413);
Epigraph answered 18/4, 2017 at 21:38 Comment(0)
S
16

First of all, let's see what you really need. Your goal here is to make request at most each 100 milliseconds, if you have a large number of albums. (Using axios.all for this matter is no different from using Promise.all, you just want to wait for all of the requests to complete.)

Now, with axios you have the interception API, allowing to plug your logic before requests. So you can use an interceptor like this:

function scheduleRequests(axiosInstance, intervalMs) {
    let lastInvocationTime = undefined;

    const scheduler = (config) => {
        const now = Date.now();
        if (lastInvocationTime) {
            lastInvocationTime += intervalMs;
            const waitPeriodForThisRequest = lastInvocationTime - now;
            if (waitPeriodForThisRequest > 0) {
                return new Promise((resolve) => {
                    setTimeout(
                        () => resolve(config),
                        waitPeriodForThisRequest);
                });
            }
        }

        lastInvocationTime = now;
        return config;
    }

    axiosInstance.interceptors.request.use(scheduler);
}

What it does is timing requests so they are performed at intervalMs milliseconds intervals.

In your code:

function getAlbums(artistID) {
    const deezerService = axios.create({ baseURL: 'https://api.deezer.com' });
    scheduleRequests(deezerService, 100);

    deezerService.get(`/artist/${artistID}/albums`)
        .then((albums) => {
            const urlRequests = albums.data.data.map(
                    (album) => deezerService
                        .get(`/album/${album.id}`)
                        .then(albumInfo => albumInfo.data));

            //you need to 'return' here, otherwise any error in album
            // requests will not propagate to the final 'catch':
            return axios.all(urls).then(console.log);
        })
        .catch(console.log);
}

This is, however, a simplistic approach, in your case you probably would like to receive the results as fast as possible for number of requests less than 50. For this, you have to add some kind of a counter inside the scheduler which will count the number of requests and delay their execution based both on the interval and the counter.

Shoreline answered 2/8, 2017 at 12:14 Comment(0)
W
8

Here is my solution using simple async setTimeout / Es6 code :

you can setup the delay in the sleep param func

const sleep = (delay) => {
  return new Promise(function(resolve) {
    setTimeout(resolve, delay);
  });
}


axios.interceptors.response.use(async function (response) {
    await sleep(3000)
    return response;
  }, function (error) {
    // Do something with response error
    console.error(error)
    return Promise.reject(error);
  });

There is also this npm package you can use : https://www.npmjs.com/package/axios-request-throttle

Wie answered 11/5, 2020 at 11:48 Comment(0)
E
0

There is a module that worked for me outside the box with a NestJS application

Throttle axios request-per-second rate with 3 lines of code. The main difference with this module and others like axios-throttled is that you don't have to create a new axios instance, and by extension don't have to fix imports project-wide. Apply once and every axios.get, post, put, delete etc is throttled.

axios-request-throttle

Emaemaciate answered 29/9, 2022 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.