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.
[lwptoc]
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 /posts
API. 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
totrue
initially and set it tofalse
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