Are you tired of catching errors with .catch methods?
Are you tired of looooong API URLs and repeating headers for each request??
Are you tired of not having an idea for handling fetch cancellation in useEffect cleanup???
Are you tired of not having a good structure to manage your requests????
Well, look who is here! Axios the savior…
By using this lovely library, you don’t need the fetch() for requests anymore, and all the above problems will be solved.
In this article, I will implement a good structure to manage requests using Axios and of course, I will explain how and why.
In the above example, I have used fetch() 3 times. Now let’s see the problems I got: 1. most parts of the request URLs are the same (Base URL) 2. I repeat the headers in all of them while they are completely identical 3. Instead of having one catch for all requests, I use the catch method for each request. if we got for instance 401 for each request they are not different, so why the catch method should be?
This is the time that Axios comes up to the scene.
1. Axios installation
npm install axios
yarn add axios
2. Create a Services folder in the src folder
services folder contains 3 folders:
1.Config folder which contains an index.js file that I put my initial config in.
there is no doubt that I installed axios, but it is useless if I just want to use it without any config:
In the above example I used axios without config and you can see that I’m repeating myself with headers and baseUrls.
Now this is what I put in src/Services/Config/index.js:
In the above code, axios.create, creates a new instance of axios and i can give it a custom config by passing an object as an argument of this create method.
This config will apply to all requests made from the api instance and when I make a request with api, I don’t have to pass headers and base URL to each request and repeat myself.☺
In the above example, I comment out my previous requests(axios without config) and use my own instance named “api” and it does exactly the same thing
Attention to the above code example: the second parameter that I pass to post and put methods is the body and I can’t put it in the config, as you can see they are different bodies.
Tip: BaseURI is the address that gets attached to the beginning of the endpoints e.g: if the base URL is ‘https://www.baseurl.com/api’ , So api(‘/users/) will become api(‘https://www.baseurl.com/api/users/’)
Tip:the headers that I used in my config has an authorization key with value of my token. i need this to be able to use api
So, now instead of Axios itself, I am going to use the api instance of Axios with my custom config.
2.ErrorHandler folder which contains index.jsx file
Yes! this file is a jsx component, BUT, as you can see it returns nothing!
We just need the function above which helps us to get rid of .catchs for each request(of course, you can handle Axios error catching with interceptors in different ways, but I am going to stick to my way).
If you are not familiar with different error statuses, here are some good tips that you can read before investigating the above code:
Error 400: indicates that the server cannot or will not process the request due to something that is perceived to be a client error (for example, malformed request syntax, invalid request message framing, or deceptive request routing).
Error 401: we need a token to set as authorization value in headers of our Axios instance config and when the user sign-in / sign up, the user receives a token and we set it to localStorage (or anywhere you want) and then set it to authorization of headers. It allows us to use API. But, tokens have an expiration time and when it gets expired or if we don’t set a token to our authorization at all, we are going to receive Error 401 that represented the request sent by the client to the server that lacks valid authentication credentials.
Error 403: it means that accessing the page or resource you were trying to reach is absolutely forbidden for some reason.
Error 404: indicates the server was unable to find what was requested. This message may also appear when the server is not willing to disclose the requested information or when the content has been deleted.
Error 429: indicates the user has sent too many requests in a given amount of time.
As you can see in the above example, we imported our Axios instance (named api) and used something named interceptors which there are two of them: the first interceptor is for requests and it does something with our request before we send it to the server and the second interceptor is for responses and it does something with the response before we get the response with .then and .catch methods.
as you can see in the above example, we imported our Axios instance (named api) and used something named interceptors which there are two of them: the first interceptor is for requests and it does something with our request before we send it to the server and the second interceptor is for responses and it does something with the response before we get the response with “.then” and “.catch” methods.
The “use” method of request requires two callbacks: the first one is the callback that gets triggered before the request is sent, and the second one is the callback that gets triggered when the request has an error.
The “use” method of response requires two callbacks: the first one is the callback that gets triggered when our response status code lies within the range of 2xx(resolved or fulfilled), and the second one is the callback that gets triggered when our response status code falls outside the range of 2xx(rejected).
In the example above, we used the response “use” method and passed a callback as the first parameter that does nothing special and just returns the response that it gets from the server without any change. BUT!, the second callback that we passed to the “use” method deals with errors and we do a lot of things with different errors instead of handling them in the “.catch” over and over again.
Response error status codes usually are 400,401,403,404,429, and some other codes and we are going to handle them in this article but you can handle as many error status codes as you want :)
The second callback of the ‘use’ method, receives an error as an argument, and this error argument has a response property which has a status property that we need, and other properties like data which has a message property that we need that.
Note: We return Promise.reject in all cases so that when the response goes through this step and goes to .then and .catch, the system knows the response is fulfilled or rejected to execute “.then” or “.catch” method.
In our example, we said…
if the status code is 400, reject and then alert with the message of response itself.
if the status code is 403, reject and then alert with the message of “you don't have permission…”
if the status code is 404, just reject.
if the status code is 429, reject and then alert with the message of “too many requests”
If the status code is 401, we obviously don’t have a valid token( expired or doesn’t set at all), so we clear the whole information from the localStorage that we receive from the user when the user sign-up / sign-in. then we send the user to the login page to log in and set a new token to be able to use api.
Be aware you can be more creative and do things more than just an alert.
Now in every file, you use this AxiosErrorHandler component, the interceptor has an eye on the api requests of that file and we don’t need to specify the same error handling in .catch methods multiple times.
Well, I put AxiosErrorHandler component in “src/index.js” to have an eye on all the api requests I make in the whole project.
3.Requests folder contains all of our request actions in different category folders (The subject of the requests has different categories) for example:
The image above, is the content of Requests folder, each folder has a file named index.js: Auth folder’s index file contains all the requests related to authentication like login, register, forgotPassword,resetPassword,… :
As you can see, we have different exported async functions for each request and in order to use it we just need to import and invoke it.
Note: remember these all are async functions and return response from the server, So we must use them asynchronously and receive the response and do whatever we want.
This is another example for Blogs folder index file and as you have noticed it contains all requests related to blogs:
Sometimes we use these fetch requests inside useEffect, but there is something you should know and that is useEffect invokes request action every time and even when the component gets unmounted and that’s the time you see this warning:
To resolve this kind of warning, we just need to cleanup our requests whenever the component gets unmounted and we do this inside useEffect cleanup function ( the function that useEffect returns is the cleanup function as you are going to see in the example below) and there are few ways we can cancel a fetch requests inside cleanup function and for our case which is request with axios instance, this is very easy:
You just need to create a controller instance and pass an object with a property named signal and the value of controller.signal as the api second parameter and then in the cleanup function all you have to do is to invoke the abort method of the controller and it will cancel the request when the component gets unmounted. now you are not going to receive that warning and your performance is better than before.
This article ends here and hopefully you have learned how to use this lovely library to manage your requests as best as you can.
Goodbye and Good luck🤞
Top comments (0)