Streamlining API Calls in Web Applications : A Comprehensive Guide
A Centralized Web API Call For Code Maintainability & Scalability
Introduction
In the early stages of my journey as a Frontend Web Developer, I encountered a recurring challenge: making API calls to fetch data from the server. While this task is essential to building interactive and data-driven web applications, I found myself writing the same code repeatedly in different components—whether using the native fetch
API or libraries like Axios
. Each time, I had to manually handle errors, manage loading states, and integrate responses into the UI. This process led my codebase complicated and made it harder to maintain and scale.
The Problem Statement: Repetitive Code and API Calls
Whether the project we have been working on or worked on is simple or complex, the data needs to be fetched from the different endpoints for different pages to power our website. During the process, we have been repeating the block of the API call function which makes our codebase difficult to maintain & scale. And, on the same hand, increases the complexity of our project.
The Solution: Centralized Web API Call
As I progressed, I discovered a better way to manage these API calls: centralizing them using custom hooks combined with TanStack Query. By creating custom hooks and leveraging useQuery
for GET requests and useMutation
for PUT, PATCH, and other methods, I was able to streamline API interactions, add caching, —all while keeping my code clean and maintainable.
Step-by-Step Guide to Implementing Centralized API Calls
Building Custom Hooks for API Calls
One of the most effective ways to centralize API calls is by creating custom hooks. Custom hooks allow you to encapsulate the logic for making API requests into reusable functions that can be shared across multiple components.
I prefer creating a separate folder named apiServices and start creating the custom hook. Here’s how my Next.js folder structure looks like:
Let’s take an example I have worked on in my project. Here, by centralizing the export functionality into the custom hook, we can easily manage the process of exporting data to Excel, handling any errors, and providing feedback to the user through a snackbar(toast) notification.
import { useMutation } from "@tanstack/react-query"; import { axioInstance } from "@/config/axiosConfig"; //streamline custom hook to make api call const useExportToExcel = ({ endpoint, mutationKey, params, fileNamePrefix, setSnackbarData, }) => { const apiEndpoint = params ? `${endpoint}?${params}` : `${endpoint}`; return useMutation( [...mutationKey], () => { return axiosInstance.get(apiEndpoint, { responseType: "blob", //necessary to handle binary response data }); }, { onSuccess: (response) => { // on success, we download the excel file, simply setting it in memory // buffer, creating a tag to get from buffer to our pc const blob = new Blob([response.data], { type: response.headers["content-type"], }); const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; const fileName = `${fileNamePrefix}.xlsx`; link.setAttribute("download", fileName); document.body.appendChild(link); link.click(); // Call your success snackbar or notification logic setSnackbarData({ show: true, severity: "success", message: "Export successful", }); }, onError: (error) => { let err_msg = error?.response?.status; setSnackbarData({ show: true, severity: "error", message: err_msg ? err_msg : "Error: Export Unsuccessful !!!", }); }, } ); }; export default useExportToExcel;
Parameter Breakdown
To better understand how the
useExportToExcel
hook works, let’s break down the parameters:endpoint
(string
): The API endpoint from which the Excel export data will be fetched.Example:
'/api/export/excel'
mutationKey
(string
): A unique key to identify the mutation, used for caching or refetching.Example:
'export-excel-data'
params
(object
): The parameters to be sent with the request, typically as query or body data.Example:
'startDate=2024-01-07&endDate=2024-11-30'
→{endpoint}?startDate=2024-01-07&endDate=2024-11-30
fileNamePrefix
(string
): A prefix for the exported Excel file name, used to customize the file name.Example:
'example'
→example.xlsx
setSnackbarData
(function
): A toast function to handle setting data for a toast snackbar notification upon success or failure.
By centralizing the export functionality into this custom hook, you can easily manage the process of exporting data to Excel, handling any errors, and providing feedback to the user through a snack bar notification.
Using the Custom Hook in a Component
Implementation of custom hook in the component for API call;
import { useState } from "react";
import useExportToExcel from "@/api/export-services-hook/useExportToExcel";
import SnackbarComponent from "../../../shared/snackbar/SnackbarComponent";
import { ExcelExportApi } from "../../../../utils/apiUrls";
const ExportExcelComponent= () => {
const [snackbarData, setSnackbarData] = useState({
show: false,
severity: "",
message: "",
});
// custom hook for excel api call
const { isLoading: excelLoading, mutate: exportExcelMutate } =
useExportToExcel({
mutationKey: ["export_due_list_excel"],
endpoint: ExcelExportApi ,
params: "startDate=2024-01-07&endDate=2024-11-30",
fileNamePrefix: "excel",
setSnackbarData: setSnackbarData,
});
const handleExcelExport = () => {
exportExcelMutate();
};
return (
<>
{snackbarData.show && (
<SnackbarComponent
show={snackbarData.show}
handleClose={handleSnackbarClose}
data={snackbarData}
/>
)}
<h1> Demo on DownLoading Excel File </h1>
<button onClick={handleExcelExport}> DownLoad Excel </Button>
</>
);
};
export default ExportExcelComponent;
Summary
With the incorporation of streamline API call, it not make the code consistency, but also helps in scaling and maintaining as the project leaps to more complexity.
That’s all for the day.
Feel Free To Cross Question.
Thank You !!