If you have been coding javascript for a while, you'd probably have known about Axios. It is a famous JS library for making HTTP request. Whether you are back-end or front-end developer, Axios is essential to access API services out there.
Alas, reliability is scarce even when we're in 2020s. Things happen, and your HTTP request might get stalled. So what do we do? In some cases, we will try again until we get the data we need. In those cases, equipping Axios with retry capability is necessary.
In this post, I'm going to show how to equip Axios with retry capability i.e resend HTTP request when server doesn't answer. First, the native way. Then, we're going to use some libraries.
I feel the need to write this tutorial since most examples of Axios are written in .then
pattern. I'm accustomed to async/await
pattern since it feels more familiar (especially if you learn other OOP languages). Performance-wise, both are internally equal.
Anyway, let's dive in to our code. I'm going to make a Node.JS project. Feel free to use whatever javascript stuff to suit your needs. Also, make sure your dependencies are fulfilled. I already installed Node.JS and NPM for this tutorial.
First, make new project using Terminal.
$ mkdir request-retry
$ cd request-retry
$ npm init -y
$ touch index.js
Then, install axios package.
$ npm install axios
Now, we're going to edit index.js
using code editor. I'm going to make HTTP request to https://mock.codes and see if it responds.
const axios = require('axios')
const myRequest = async () => {
try {
const myConfig = {
headers: {
Authorization: 'Basic lorem12345'
}
}
const req = await axios.get('https://mock.codes/200', myConfig);
console.log(req.data);
} catch (error) {
console.log(error.response.data);
}
}
myRequest();
Now, run index.js
$ node index.js
and we will get this result
{ statusCode: 200, description: 'OK' }
Things are okay, right? Now, I'm going to rig this HTTP request by setting an unreasonably low timeout. To do that, add timeout
in the request config. Let's check index.js
again and edit myConfig
so it looks like this.
const myConfig = {
headers: {
Authorization: 'Basic lorem12345'
},
timeout: 10 // 10ms timeout so servers hate you
}
If I run $ node index.js
again, I'll probably get something like this.
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'data' of undefined
What happened? Due to unfinished request, req
doesn't get data from server. Therefore, its value is undefined
. We can't get keys from undefined
, hence the error.
It is time to implement Axios with retry capability. But before going any further, I want to make clear when referring to retry
, mostly we want to have control over two things:
- How many times we want to retry
- how long we want to wait for each trial
There are two main ways to do this:
- Implement directly
- Use package
Direct Implementation
This option means doing everything from scratch. It's not too difficult, though. It is suitable option when we just need few types of request in our code and adding package would burden the app.
One simple approach is enveloping every request with loop. Now let's say I'm willing to retry 3 times and 50 miliseconds for each request. This is the example of working code.
const axios = require('axios');
const myRequest = async () => {
try {
const retries = 3 // amount of retries we're willing to do
const myConfig = {
headers: {
Authorization: 'Basic lorem12345'
},
// we're willing to wait 50ms, servers still hate you
timeout: 50
}
for (var i=0; i<retries; i++) {
try {
const req = await axios.get('https://mock.codes/200', myConfig);
if (req) {
console.log(req.data);
break;
} else {
console.log('cannot fetch data');
}
} catch (error) {
console.log('cannot fetch data');
}
}
} catch (e) {
console.log(e);
}
myRequest();
}
It's quite long, but if we're not doing it often across one project, this solution fits nicely.
Use Package
There are times when we have to connect to many endpoints with different characteristics. In such circumstance, using package is justified.
There are 3 famous packages that satisfy our needs:
- retry, a general purpose retry operation.
- axios-retry, most popular retry add-on for Axios
- retry-axios, second most popular retry add-on for Axios
I will use retry-axios
since it provides easier implementation on async/await
pattern. Now don't forget to read on its documentation. Also, don't forget to install it using Terminal.
$ npm install retry-axios
This is an example of working code.
const rax = require('retry-axios');
const axios = require('axios');
rax.attach();
const myRequest = async () => {
try {
const myConfig = {
raxConfig: {
retry: 5, // number of retry when facing 4xx or 5xx
noResponseRetries: 5, // number of retry when facing connection error
onRetryAttempt: err => {
const cfg = rax.getConfig(err);
console.log(`Retry attempt #${cfg.currentRetryAttempt}`); // track current trial
}
},
timeout: 50 // don't forget this one
}
const req = await axios.get('https://mock.codes/200', myConfig);
console.log(req.data);
} catch (error) {
console.log(error);
}
}
myRequest();
Instead of doing loop, I basically attach retry-axios
object to Axios. My part is handling config for the request. It is much simpler and delivers same result as direct implementation.
That's it! Now we can make Axios more reliable in sending HTTP request.
Do you find it useful, informative, or insightful ?
Do you find mistakes in my tutorial ?
Do you have any questions?
Feel free to comment below 👇 and let me know.
Top comments (7)
How to implement such functionality on post request
For example: User hits a login button it will send post request but during hitting that button the internet is low or off, after certain time if the internet is on that api needed to called automatically when the internet gets on.
You can wrap the POST request as usual, then adjust the timeout accordingly. If the network is unstable, set timeout to 3 seconds (3000 in code) and set retry to 3-5 times. If login is successful, user will be redirected immediately. If it failed, throw notification that login failed due to network issue, and user can try to log in again.
Be warned that it has trade-off of higher traffic for server.
Find the best configuration between timeout and retries that suit your needs.
Hi, If I dont want use the timeout , I just do the retries when my api have a error status 400 or 500. it can work?. because dont work me
Hi,
It's okay to not use timeout.
In this case, if you receive
400
or500
status, it will automatically retry the request.However, please note that those response are considered
error
, so it will be catched.To handle
400
or500
status, put your logic aftercatch(error)
Hope this helps.
Hi, this is not working for me. I tried and it only prints for first retry and after that comes out of the condition
Hi, thanks for visiting.
Could you share your code and API you are trying to hit, please? This post primarily deal with retry mechanism. In your case, I guess it is about handling the response.
In this case, response of
400
and500
will cause it to try again. You could check the response, if the response is200
, then there's no need to retry. Your request is success.However, some API give
200
status for failed request. So you need to handle it manually.How pass headers to request with rax? not global