What is Axios

Axios stands as a promise-based HTTP client that facilitates seamless asynchronous HTTP requests, both in the browser and Node.js environment. Its support for diverse request and response formats, alongside features like interceptors and error handling mechanisms, makes it a developer’s go-to choice.

Creating the Axios Instance

import Axios from "axios"; const axios = Axios.create({});

The code snippet above demonstrates how to create an Axios instance. This instance is a base configuration for making API requests throughout your application.

Asynchronous Store Import

// Retrieve store from Redux if you are using Redux const getStore = async () => { const { store } = await import('<path-to-redux-store>/store.js'); return store; };

Introducing a dynamic import! This ingenious approach fetches the Redux store asynchronously. This is incredibly useful when dealing with asynchronous operations like loading user tokens or other dynamic data.

Setting Up the Request Interceptor

axios.interceptors.request.use( async function (config) { // Retreive token from Redux OR localStorage or .... const store = await getStore(); const token = store?.getState()?.user?.token; if (token) { config.headers["Authorization"] = `Bearer ${token}`; config.headers["Access-Control-Allow-Credentials"] = true; } config.headers["Content-Type"] = "application/json"; config.credentials = "same-origin"; config.baseURL = baseURL; return config; }, function (error) { return Promise.reject(error); } );

The request interceptor takes center stage here. This is where we have the opportunity to modify the configuration of each request before it’s dispatched. This code snippet highlights the injection of an authentication token into the request headers, fetched from the Redux store. It also sets common headers like content type and credentials.

Response Interceptor for Error Handling

axios.interceptors.response.use( (res) => { return res; }, (error) => { if (error?.response?.status === 403) { // Handle forbidden error } if (error?.response?.status === 401) { // Handle unauthorized error (e.g., log out the user) } throw error; // Propagate the error } );

The response interceptor is your safety net against errors. Here, we’re focusing on HTTP error codes 401 (unauthorized) and 403 (forbidden). When these errors occur, you can take appropriate actions, like logging out the user. Remember, the error must be thrown again to ensure it’s captured by the appropriate catch block.

Complete Code

// axios.js import Axios from "axios"; // Dynamic import const getStore = async () => { const { store } = await import('<path-to-redux-store>/store.js'); return store; }; const axios = Axios.create({}); const serverUrl = process.env.REACT_APP_SERVER_URL; export const baseURL = `${serverUrl}`; axios.defaults.timeout = 120000; // Milliseconds axios.interceptors.request.use( async function (config) { // Retreive token from Redux OR localStorage or .... const store = await getStore(); const token = store?.getState()?.user?.token; if (token) { config.headers["Authorization"] = `Bearer ${token}`; config.headers["Access-Control-Allow-Credentials"] = true; } config.headers["Content-Type"] = "application/json"; config.credentials = "same-origin"; config.baseURL = baseURL; return config; }, function (error) { return Promise.reject(error); } ); axios.interceptors.response.use( (res) => { return res; }, (error) => { if (error?.response?.status === 403) { // Handle forbidden error } if (error?.response?.status === 401) { // Handle unauthorized error (e.g., log out the user) } throw error; // Propagate the error } ); export default axios;

Enhancing API Interactions with apiHelpers.js

Efficiency and reusability are key when dealing with API requests. The apiHelpers.js file streamlines common request patterns, enabling seamless communication with the backend.

// apiHelpers.js import axios from "./axios"; export const getRequest = async ({ url, params = {} }) => { try { const res = await axios.get(url, { params }); return res.data; } catch (err) { return err; }; }; // OR =====> In case of Redux Thunk <====== // export const getRequest = async ({ url, params = {}, thunkApi }) => { // try { // const res = await axios.get(url, { params }); // return res.data; // } catch (err) { // return thunkApi.rejectWithValue(err); // return err; // }; // }; export const postRequest = async ({ url, data = {}, params = {} }) => { try { const res = await axios.post(url, data, { params }); return res.data; } catch (err) { return err; }; }; export const postFormDataRequest = async ({ url, data = {}, params = {} }) => { try { const res = await axios.post(url, data, { params, headers: { "Content-Type": "multipart/form-data" }, }); return res.data; } catch (err) { return err; }; }; export const patchRequest = async ({ url, data = {}, params = {} }) => { try { const res = await axios.patch(url, data, { params }); return res.data; } catch (err) { return err; }; }; export const patchFormDataRequest = async ({ url, data = {}, params = {} }) => { try { const res = await axios.patch(url, data, { params, headers: { "Content-Type": "multipart/form-data" }, }); return res.data; } catch (err) { return err; }; }; export const putRequest = async ({ url, data = {}, params = {} }) => { try { const res = await axios.put(url, data, { params }); return res.data; } catch (err) { return err; }; }; export const deleteRequest = async ({ url, params = {} }) => { try { const res = await axios.delete(url, { params }); return res.data; } catch (err) { return err; }; };

Orchestrating API Requests

// Making GET Requests import { getRequest } from "./apiHelpers"; const fetchData = async () => { try { const data = await getRequest({ url: "/api/data" }); console.log("Fetched data:", data); } catch (error) { console.error("Error fetching data:", error); } }; // OR ====> using with Redux Thunk <====== // export const contactUsApi = createAsyncThunk("user/fetchData", (params, thunkApi) => { // return getRequest({ url: '/api/data', params, thunkApi }); // });

Conclusion: Elevating API Interactions with Axios and Streamlined Helpers

The Axios configuration file outlined in this article offers a comprehensive guide to handling API requests in a React application. From configuring the base URL to skillfully managing request and response interceptors, this blueprint equips developers with the tools needed for effective communication with APIs.

By internalizing the intricacies of Axios configuration, developers can seamlessly orchestrate API interactions, and elegantly manage errors. Armed with this knowledge, you’ll confidently build applications that fluidly communicate with backend APIs, fostering a superior user experience.

In this discourse, we have meticulously deconstructed an Axios configuration file tailored for dynamic API requests in React applications. With an illuminating breakdown of each code segment and its relevance, we have enabled you to grasp how Axios can be wielded to orchestrate API requests with finesse. Whether you’re a newcomer to Axios or an adept seeking to refine your skills, this guide empowers you to navigate the intricacies of HTTP requests with panache.