DEV Community

Cover image for Centralize API calls in Web Application - A must-have guide
Chhakuli Zingare for CreoWis

Posted on • Originally published at creowis.com

Centralize API calls in Web Application - A must-have guide

Hey there! I'm Chhakuli, working as a Front-End developer for a while now. Today, I want to share with you how you can make your app a lot better by changing how you handle API calls. Don't worry if you're new to this stuff - I'll explain everything in simple terms.

As developers, we constantly deal with APIs to fetch or send data, and in larger applications, API management can easily become chaotic. If you’re working with a framework like Next.js, you already have a robust framework that supports both client-side rendering (CSR) and server-side rendering (SSR). This dual capability makes Next.js a perfect environment to centralize API calls, offering flexibility and simplicity.

The Common Problem

Picture this scenario: You have a large Next.js app. It's functional, but there's a recurring issue. Every time data needs to be fetched from the server (that's what an API call does), you find yourself writing repetitive code. It's like cooking dinner and having to get out all the pots and pans each time you want to make a meal. It becomes a real pain!

Here's what the code often looks like:

const getData = async () => {
  try {
    const response = await fetch('https://my-api.com/data', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    });
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Oops, something went wrong:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

This code might be scattered all over the app. It's messy and hard to keep track of. Plus, if you want to change something (like how errors are handled), you'd have to change it in multiple places. Not fun!

My Light Bulb Moment

One day, in a code review session, I got feedback from my senior. It was kind of like making a special kitchen helper who always gets your pots and pans ready for you.

PR feedback

The Solution: Centralizing API Calls

The solution to this problem is to create an "HTTP service." Don't let the fancy name scare you - it's just a file where all API-related code is centralized. Here's how to implement it:

  1. Create a new file called httpService.ts. This file will be in charge of all API calls.

  2. In this file, create a main function called request. This function knows how to talk to the server and get the required data.

  3. Add some helper functions like get, post, patch, and del (use del instead of delete because delete is a reserved word in JavaScript).

Here's what the httpService.ts might look like:

const API_BASE_URL = 'https://my-api.com';

const defaultHeaders = {
  'Content-Type': 'application/json',
};

const request = async (method, url, payload, customHeaders) => {
  const headers = { ...defaultHeaders, ...customHeaders };
  let body;

  if (payload) {
    body = JSON.stringify(payload);
  }

  try {
    const response = await fetch(`${API_BASE_URL}${url}`, {
      method,
      headers,
      body,
    });

    const data = await response.json();

    if (!response.ok) {
      throw { status: response.status, data };
    }

    return data;
  } catch (error) {
    console.error(`Oops, something went wrong with ${url}:`, error);
    throw error;
  }
};

const get = (url, customHeaders) => request('GET', url, null, customHeaders);
const post = (url, payload, customHeaders) => request('POST', url, payload, customHeaders);
const patch = (url, payload, customHeaders) => request('PATCH', url, payload, customHeaders);
const del = (url, customHeaders) => request('DELETE', url, null, customHeaders);

export { get, post, patch, del };
Enter fullscreen mode Exit fullscreen mode

It might look like a lot, but the cool thing is, you only need to write this once, and then you can use it throughout your app.

Using the New HTTP Service

Now, when you want to get data from your server, you can do it like this:

import { get } from '../httpService';

const getUserData = async (userId) => {
  try {
    const data = await get(`/users/${userId}`);
    return data;
  } catch (error) {
    console.error('Could not get user data:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

See how much simpler that is? You don't have to worry about all the details of making an API call anymore. The httpService takes care of all that for you.

Why This Change is Awesome

Let me tell you why this new way of doing things is so great:

  1. Less Repetition: I don't have to write the same API code over and over again. It's like having a recipe that I can use for lots of different meals.

  2. Easier to Fix Errors: If something goes wrong with my API calls, I know exactly where to look. It's all in one place!

  3. Simpler to Make Changes: If I need to change how my API calls work (like adding some security stuff), I can do it in one place, and it updates everywhere in my app.

  4. Cleaner Code: My components (the building blocks of my app) look much neater now. They're not cluttered with all that API code.

  5. Easier to Test: When I want to make sure my app is working correctly, it's much easier to test my API calls now.

  6. Better Security: I can add things like authentication tokens to all my API calls really easily now.

  7. Room to Grow: As my app gets bigger, it's super easy to add new types of API calls.

Real-Life Example: Login System

Let's look at a real example of how this helps. Say you're building a login system for your app. Before, you might have done something like this

const login = async (username, password) => {
  try {
    const response = await fetch('https://my-api.com/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ username, password }),
    });
    const data = await response.json();
    if (!response.ok) {
      throw new Error('Login failed');
    }
    return data;
  } catch (error) {
    console.error('Login error:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

Now, with my new httpService, it looks like this:

import { post } from '../httpService';

const login = async (username, password) => {
  try {
    const data = await post('/login', { username, password });
    return data;
  } catch (error) {
    console.error('Login error:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

Much cleaner, right? If you need to change how your login works (like adding a new security check), you can do that in the httpService, and it will automatically apply to all your API calls.

The Journey of Implementing This Change

Implementing this change in an existing app isn't always easy. Here's a general process you might follow:

  1. Planning: Spend time planning how the httpService should work. Make sure it can handle all the different types of API calls you might need.

  2. Creating the Service: Writing the httpService itself takes some time. Consider error handling, how to make it flexible for different types of requests, and how to make it easy to use.

  3. Updating Your Code: This is the big job. Go through your entire app and replace all your old API calls with your new httpService calls. It takes a while, but it's worth it.

  4. Learning and Adjusting: As you start using the new system, you'll likely find ways to improve it. It's an ongoing process of learning and refining.

Lessons I Learned

Going through this process can teach you a lot. Here are some key takeaways:

  • Planning Pays Off: Taking the time to plan your approach before you start coding can save you a lot of headaches later.

  • Consistency is Key: Having a standard way of doing API calls across your app makes everything easier to understand and maintain.

  • Flexibility Matters: Make sure the httpService is flexible enough to handle different types of API calls. This will be super helpful as your app grows.

  • It's Okay to Iterate: You might not get everything perfect the first time, and that's okay. Keep improving the httpService as you use it more.

Wrapping Up

Centralizing API calls in a Next.js app can significantly improve code quality and maintainability. It's a big change, but it makes life as a developer much easier. Your code becomes cleaner, it's easier to add new features, and when something goes wrong, it's much easier to figure out why.

If you're working on a Next.js app (or any React app, really) and you're feeling overwhelmed by API calls everywhere, give this approach a try. It might take some work upfront, but it's worth it in the long run.

Remember, good code isn't just about making things work - it's about making things work well and making your life as a developer easier. So don't be afraid to step back, look at the big picture, and make changes that will help you in the long run.

Happy coding, everyone! And if you try this out in your own projects, share your experience. Did it help? Did you do things differently? Let others know! Don't forget to share this blog with your peers to spread the knowledge and inspire others!


We at CreoWis believe in sharing knowledge publicly to help the developer community grow. Let’s collaborate, ideate, and craft passion to deliver awe-inspiring product experiences to the world.

Let's connect:

This article is crafted by Chhakuli Zingare, a passionate developer at CreoWis. You can reach out to her on X/Twitter, LinkedIn, and follow her work on the GitHub.

Top comments (10)

Collapse
 
anandbaraik profile image
Anand-Baraik

Insightful read. Learnt something new which can be used in some of my projects. Thanks for sharing :)

Collapse
 
chhakuli_zingare_2a0ad5f8 profile image
Chhakuli Zingare

Thank you, Anand! 😊 I'm glad you found it useful and can apply it to your projects. Best of luck with your implementations!

Collapse
 
pranita09 profile image
Pranita

Useful information. I have tried same approach before, but this is much better than that. Got to learn something, thanks for sharing!

Collapse
 
chhakuli_zingare_2a0ad5f8 profile image
Chhakuli Zingare

Thanks so much, Pranita! I’m happy to hear this approach works better for you. It's great that you could learn something new. 😊

Collapse
 
syketb profile image
Syket Bhattachergee

Amazing concepts that make developers' lives easier. Thanks for sharing!

Collapse
 
chhakuli_zingare_2a0ad5f8 profile image
Chhakuli Zingare

Thanks, Syket! 🙌.

Collapse
 
atapas profile image
Tapas Adhikary

It certainly helps in getting all the calls at one place, thus improves in code maintainability.

Collapse
 
chhakuli_zingare_2a0ad5f8 profile image
Chhakuli Zingare

Thanks a lot, Tapas! 😊 Yes, centralizing the calls definitely helps with maintainability.

Collapse
 
prachi_sahu profile image
Prachi Sahu

Great blog! Thanks for sharing.

Collapse
 
chhakuli_zingare_2a0ad5f8 profile image
Chhakuli Zingare

Thank you so much, Prachi! 😊 I’m really happy you enjoyed the blog. Thanks for the support!