Organizing API calls in frontend - why & how

Organizing API calls in frontend - why & how
Photo by Pavan Trikutam / Unsplash

API calls are often a significant part of most web applications, if not the most critical aspect. However, many projects lack proper organization for these calls, leading developers to scatter API calls throughout the codebase.

Why should we care?

Maintainability: Writing API calls haphazardly can quickly lead to a tangled mess. This approach often results in repeated imports of API libraries across various files, leading to code duplication and increased chances of errors. By centralizing API calls and categorizing them, we can eliminate redundancy and reduce the risk of future bugs, making the codebase clearer and easier to navigate.

Performance Optimization: Well-organized API calls can enhance performance by minimizing unnecessary requests, implementing caching strategies, and batching requests when suitable. This organization simplifies the use of libraries like React Query, RTK Query, and SWR.

Testing: Having a structured approach to API calls facilitates the writing of unit and integration tests. With a clear organization, it’s easier to mock API responses effectively, ensuring our application functions as intended.

How to organize

We can streamline our API calls by centralizing them through a Data Access Layer (DAL) using the repository pattern. We'll utilize Axios for API requests and JSONPlaceholder as our endpoint source.

To start, we'll create a folder called services to house all our API-related functionality. Inside this folder, we'll add a file named apiClient.js, where we'll import the Axios library and set up a custom Axios client with our shared API configurations.

/services/apiClient.js

Next, we'll create separate files (repositories) for each set of API resources, as API endpoints are typically organized by resource groups. For our example, JSONPlaceholder has resource groups like /posts, /todos, and /users. To keep it simple, we'll focus on just /posts and /todos. While the repository pattern traditionally uses classes, we’ll simplify things by using plain objects.

/servicecs/postsRepo.js

Let's create another similar repo for /todos endpoints

/services/todosRepo.js

Now that we are done with creating our repos and client, let's consolidate everything into a single, organized object. We’ll add an index.js file in the /services directory to gather all our repositories while maintaining their resource group organization.

/services/index.js

Now we can use this $api object anywhere we need to call our APIs

As you can see, this approach is much cleaner than repeating API calls throughout the application. If we need to change a URL or the format of the data, we only have to update the apiClient or relevant repositories, making maintenance easier.