Next.js 13+ with Axios – Client Side & Server Side HTTP Calls with Error Handling

In this article, we will discuss in detail how to harness the power of Next js 13.2+ when combined with popular HTTP client Axios for building dynamic data-driven applications. We will discuss in detail how to use the Axios library on both Client-side and Server-Side to make various types of HTTP calls like GET or…

By.

min read

In this article, we will discuss in detail how to harness the power of Next js 13.2+ when combined with popular HTTP client Axios for building dynamic data-driven applications.

We will discuss in detail how to use the Axios library on both Client-side and Server-Side to make various types of HTTP calls like GET or POST. The most important aspect, Error Handling is also will demonstrate with the help of simple components constructions.

Next.js is a React framework that provides a number of useful features like Server-side rendering and helps in building SEO-friendly, production-ready web applications.

Axios is a promise-based HTTP client for JavaScript applications and it’s widely used to make AJAX requests. It is a prior choice for handling HTTP requests in applications due to its simplicity, flexibility and support for the latest browsers.

 

Why use Axios with Next js?

Axios works seamlessly great on both the Client or Server Sides, which makes it fully compatible to work with Next js application flows.

As Axios is a promise-based API, it supports interceptors that can handle requests, responses and handle errors effectively in much more optimized and cleaner ways.

 

How to use Axios with Next js 13.2?

Follow these quick steps to start using Axios in the Next js application, thereafter we will move into more advanced implementations to discuss its usage on Client-Side and Server-Side with various example coming on the way:

Step 1 – Setting Up Next.js Application
Step 2 – Install Axios in the Next js Application
Step 3 – Create an Axios Instance
Step 4 – Making API Requests

 

Step 1 – Setting Up Next.js Application

First of all, let’s create a new Next js application by executing below create-next-app npx command by providing the app name:

npx create-next-app my-axios-app

 

Step 2 – Install Axios in the Next js Application

After the application is ready, you can install Axios as a dependency by running the command in the terminal window at your project root:

npm install axios

 

Step 3 – Create an Axios Instance

For keeping our Axios configurations clean and managed in one place, we will create an install of Axios. Create a file called axios.js under the libs folder and update it with the following:

// lib/axios.js

import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://api.example.com', // Replace with your API endpoint
  timeout: 5000, // Set a timeout for requests (in milliseconds)
  headers: {
    'Content-Type': 'application/json', // Set the default content type for request headers
    Authorization: 'Bearer your-token', // Set authorization headers if needed
  },
});

export default instance;

Here we have various optional configurations like the base URL pointing to the API server. This can be changed from one place very easily.

 

Step 4 – Making API Requests

Now, we will create a page in the Next js project that will make an API request using Axios. Create a new file, such as posts.js, and add the following code in it:

// pages/posts.js

import React, { useEffect, useState } from 'react';
import axiosInstance from '../libs/axios';

const Posts = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    axiosInstance.get('/posts')
      .then((response) => {
        setPosts(response.data);
      })
      .catch((error) => {
        console.error('Error fetching posts:', error);
      });
  }, []);

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Posts;

In the above example page, we import our Axios instance and use it to make a GET request to /postsAPI. The retrieved data from the HTTP call is then displayed on the page by iterating it in a list using map.

 

Handling Errors

In the previous section, we created a simple example to trigger a GET HTTP call using Axios. In this section will get to know how to easily handle API errors and also maintain a good user experience.

 

Creating an Error Component

Let’s start by creating a reusable error component that we can display when an API call fails. Create a new file called ErrorComponent.js:

// components/ErrorComponent.js

import React from 'react';

const ErrorComponent = ({ error }) => {
  return (
    <div>
      <h2>Oops! An error occurred:</h2>
      <p>{error.message}</p>
    </div>
  );
};

export default ErrorComponent;

 

Handling Errors in API Calls

Now, we will integrate the above-created error component into our API call. We will modify the Posts component to handle errors:

// pages/posts.js

import React, { useEffect, useState } from 'react';
import axiosInstance from '../axios';
import ErrorComponent from '../components/ErrorComponent';

const Posts = () => {
  const [posts, setPosts] = useState([]);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    axiosInstance.get('/posts')
      .then((response) => {
        setPosts(response.data);
        setIsLoading(false); // Set loading to false on success
      })
      .catch((err) => {
        setError(err);
        setIsLoading(false); // Set loading to false on error
      });
  }, []);

  if (isLoading) {
    return <p>Loading...</p>; // Display loading state
  }

  if (error) {
    return <ErrorComponent error={error} />; // Display error component
  }

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Posts;

In the above example, we introduced three new states error, isLoading, and updated the Posts component to handle them:

  • error: Holds the error object when an API call fails.
  • isLoading: Indicates whether the data is still loading.
  • We are setting isLoading to true initially and set it to false after the API call completes, even if its a  success or failure.

 

Handling Loading States

This section will focus on creating a loading state to inform users if data is still getting fetched from a remote HTTP API.

 

Creating a Loading Component

First create a very simple new file called LoadingComponent.js:

// components/LoadingComponent.js

import React from 'react';

const LoadingComponent = () => {
  return <p>Loading...</p>;
};

export default LoadingComponent;

 

Handling Loading State in API Calls

Next, we will integrate the loading component into our API call by modifying the Posts component:

// pages/posts.js

import React, { useEffect, useState } from 'react';
import axiosInstance from '../axios';
import ErrorComponent from '../components/ErrorComponent';
import LoadingComponent from '../components/LoadingComponent';

const Posts = () => {
  const [posts, setPosts] = useState([]);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    axiosInstance.get('/posts')
      .then((response) => {
        setPosts(response.data);
        setIsLoading(false);
      })
      .catch((err) => {
        setError(err);
        setIsLoading(false);
      });
  }, []);

  if (isLoading) {
    return <LoadingComponent />; // Display loading component
  }

  if (error) {
    return <ErrorComponent error={error} />;
  }

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Posts;

In the above-updated Posts component, we added a LoadingComponent that displays a loading message while the API call is in progress. It will be visible until isLoading is set to false.

 

Using Axios for Client and Server Side with Examples

In this other detailed and informative section, you will learn how to use Axios to make HTTP calls on the Client as well as on the Server side with examples:

 

Client-Side API Calls

Let’s have a look at how to make various types of HTTP calls including GET and POST on client-side using Axios:

 

1 – GET Request – Fetch Data

You can make client-side GET requests to fetch data from an external API by using the axios.get() method as shown below:

// pages/index.js (Client-Side) - Using Axios

import React, { useEffect, useState } from 'react';
import axios from 'axios'; // Import Axios

const Home = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/posts') // Use axios.get instead of fetch
      .then((response) => {
        setData(response.data);
      })
      .catch((error) => {
        console.error('Error fetching data:', error);
      });
  }, []);

  return (
    <div>
      <h1>Client-Side GET Request with Axios</h1>
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default Home;

Here we used the useEffect hook to make the call after the view is rendered as this is the client-side execution of the HTTP call.

 

2 – POST Request – Sending Data

Here we will make the POST call using the axios.post by wrapping it in async await.

// pages/contact.js (Client-Side) - Using Axios

import React, { useState } from 'react';
import axios from 'axios'; // Import Axios

const Contact = () => {
  const [message, setMessage] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      const response = await axios.post('/api/send-message', { message }, {
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (response.status === 200) {
        console.log('Message sent successfully');
      } else {
        console.error('Failed to send message');
      }
    } catch (error) {
      console.error('Error sending message:', error);
    }
  };

  return (
    <div>
      <h1>Contact Us</h1>
      <form onSubmit={handleSubmit}>
        <textarea
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          placeholder="Enter your message"
        />
        <button type="submit">Send</button>
      </form>
    </div>
  );
};

export default Contact;

The post-HTTP call is getting triggered Client side at the click of a button to submit a contact form.

 

Server-Side API Calls

Now we will have a look on making HTTP calls including GET and POST on server side, which are triggered before the page is loaded and rendered on the client side:

 

1 – Server-Side Data Fetching – getServerSideProps

To fetch data on the server side we use getServerSideProps hook which is useful for SEO because the data is available at build time. Here’s an example:

// pages/posts/[id].js (Server-Side)

import axios from 'axios';

const Post = ({ post }) => {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
};

export async function getServerSideProps({ params }) {
  const response = await axios.get(
    `https://jsonplaceholder.typicode.com/posts/${params.id}`
  );
  const post = response.data;

  return {
    props: { post },
  };
}

export default Post;

We are making get calls using the axios.get() method inside the getServerSideProps after the data is received is it passed props to the Post and the page is rendered

2 – Static Site Generation (SSG) – getStaticProps

The static Site Generation method generated the HTML at build time, which is great for performance. Here’s an example of using getStaticProps:

// pages/index.js (Server-Side)

import axios from 'axios';

const Home = ({ posts }) => {
  return (
    <div>
      <h1>Static Site Generation (SSG)</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export async function getStaticProps() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/posts'
  );
  const posts = response.data;

  return {
    props: { posts },
  };
}

export default Home;

 

3 – Incremental Static Regeneration (ISR) – getStaticPaths

The incremental Static Regeneration method allows to statically generate pages on-demand:

// pages/posts/[id].js (Server-Side)

import axios from 'axios';

const Post = ({ post }) => {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  );
};

export async function getStaticPaths() {
  // Fetch a list of post IDs from your API
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/posts'
  );
  const posts = response.data;
  
  const paths = posts.map((post) => ({
    params: { id: String(post.id) },
  }));

  return {
    paths,
    fallback: false, // Set to true for ISR with fallback
  };
}

export async function getStaticProps({ params }) {
  const response = await axios.get(
    `https://jsonplaceholder.typicode.com/posts/${params.id}`
  );
  const post = response.data;

  return {
    props: { post },
  };
}

export default Post;

The examples we represented above, cover all the major types of API calls we can make in Next js both on the client-side and server-side. Make sure to choose the best approach which suits your project’s requirements.

 

Leave a Reply

Your email address will not be published. Required fields are marked *