I want to be clear from the very start, this is not a post of why "you should always avoid fetch", as for what you do and you know the limitations and how to get around it, and you are happy with that, that's totally ok for me.
But, I often see comments across our team where people ask why we use axios
, a library to fetch data from a resource, then using the native fetch
library.
And to be fair is a totally valid question in my opinion.
We could argue on the advantages on using one instead of the other and vice-versa, like you don't need any dependencies for fetch
(unless you need to support old browsers and use a polyfill) or the other can give you a better degree of tuning, but I'm a practical person and I prefer to show practical examples, and let the code explain why I prefer X over Y.
Let's have this simple case, where you have to fetch some data from an API, and I want to check if the request is successful or not.
Normally I prefer to wrap calls like this into a try..catch
statement, so I can catch the error if the request fails:
const axios = require('axios');
const TEST_ENDPOINT = 'https://somedomain.com/api/someendpoint';
(async () => {
try {
await fetch(TEST_ENDPOINT);
console.log('using fetch: all good');
} catch (error) {
console.error('using fetch: error');
}
})();
(async () => {
try {
await axios.get(TEST_ENDPOINT);
console.log('using axios: all good');
} catch (error) {
console.error('using axios: error');
}
})();
My expectation would be that they both act the same, if the request is successful, I'll se the all good
message, but if the API returns anything else than a 200 OK
status header, it should throw an error.
But if you run the code above, this will happen:
using fetch: all good
using axios: error
Why with fetch
I get the all good
message?
That's because fetch
doesn't throw any error if the request fails, it will just rely on the code to handle that by looking at the response from the request, using either the status
or ok
properties,
while with axios
if a request fails, it will throw an error immediately.
So to make your fetch
request works properly, you will need to add some extra code:
(async () => {
try {
const result = await fetch(TEST_ENDPOINT);
if (!result.ok) {
throw new Error('Not found');
}
console.log('using fetch: all good');
} catch (error) {
console.error('using fetch: error');
}
})();
Again, if you are ok to add this extra check, I'm totally ok to use fetch
.
Now, let's say that we are expecting the response to be a JSON object, and we want to use that in our code.
With axios
, you just need to fetch the data
property from the axios response, and it's already a JSON object, no need to do any transformation or call any functions, it's ready to go.
With fetch
you have to get the response from the request, and use the json()
function to transform the raw data into a JSON object.
When you add with the previous error checking, to do the same exact job, you will have your code that will look like this:
// Fetch
const response = await fetch(TEST_ENDPOINT);
if (response.status !== 200) {
throw new Error('Not found');
}
const data = await response.json();
// Axios one liner
const { data } = await axios.get(TEST_ENDPOINT);
The code above does the same exact thing, but with axios
is one line of code, while with fetch
is 5.
And when you build large applications, it can become tedious to keep adding the same controls, unless you create your own wrap function, which again is more code that you have to maintain.
Is this a deal breaker for you? Maybe not, maybe you do just an handful of requests in your application, and that's totally fine to use fetch
, especially if you don't want to have more dependencies.
What about doing requests that don't use the GET
method?
Let's say I want to send some data to an API?
With fetch
you will have something like this:
const yourPostData = {
name: 'Alessio',
age: 25,
};
const response = await fetch('https://example.com/profile', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(yourPostData),
});
const result = await response.json();
So you have to pass an object, telling fetch
to use the POST
method, transform the data into a string, and pass the headers to tell it to encode it as application/json
.
Then to read the response we'll need to transform the data back to JSON.
The same above with axios
is again, excluding the input data, a one liner code:
const yourPostData = {
name: 'Alessio',
age: 25,
};
const { data } = await axios.post('https://example.com/profile', yourPostData);
Personally I prefer to have brevity of code, at the expense of a small dependency. Again, it's more than that, these are just two simple examples to explain my point in the argument, and if you are ok to write more verbose code, or create your own wrapper, that's totally ok.
Top comments (1)
What you mentioned in the article was talked about lots of times.
You're saying that there are something more than what you've mentioned, so please share it instead.