Skip to main content

fetch() to send http requests

How do we send requests to the server from our client?

We make HTTP requests from our React components.

client to server communciation
client to server communication

In Next.js, you can send asynchronous HTTP requests using the fetch API or a library like axios. We'll use the fetch API to send and respond to http requests.

fetch() for asynchronous data requests

fetch() is the built-in api for making network requests - specifically HTTP requests such as GET, POST, etc. fetch() is available in both browser-based client applications and Node.js environments. We use fetch() to request data from public APIs that provide data such as a “quote of the day” service or a weather service API.

fetch() returns a Promise that, when fulfilled, contains the response data in .then() or returned with async/await. The response object has several properties:

  • response.ok - a boolean value, true if the response status code is between 200–299 (successful).
  • response.status - The numeric HTTP status code (like 200, 404, 500).
  • response.url - the final URL of the response
  • response.json() - parses body as JSON, returns a Promise.
  • response.text() - reads the body as plain text.
  • response.blob() - reads the body as binary data (e.g., for images).
  • response.formData() - reads the body as form data.

Find more information on the fetch response object

We need to determine what requests our application will make. For example, to implement the Create, Read, Update and Delete ( CRUD ) operations on our set of items, we'll make the following requests:

actionroutehttp request method
retrieve list items/
retrieve a specific item/[id]GET
add a new item/POST
update a specific item/[id]PUT
delete a specific item/[id]DELETE

fetch to retrieve a list

This example uses the fetch API to retrieve the set of items `.

async function Items() {
const [UGAitems, setItems] = useState<ItemType[]>([]);

useEffect(() => {
const fetchItems = async() => {
const response = await fetch('/api/items');
if (!response.ok) throw new Error('Network response was not ok');

const data = await response.json();
setItems(data.items);
};

fetchItems();
}, []);
return (
{UGAitems.map((item) => (
<Item key={item._id} item={item} />
))}
)
}

The asynchronous fetch call makes a GET request ( GET is the default ) and returns a Response object on resolve of the promise. data.json() parses the body of Response as JSON. It returns a promise that resolves to the array of posts. We use map() to create each post item.

info

Read the next.js documention on fetch to learn more.

fetch to post a new user

This example uses the fetch API to send a new user to the server. headers specifies that the request body is JSON data. body contains the actual user data to send in the request. data is converted to a JSON string with JSON.stringify(). The JSON string is sent to the server in the body of the request.

async function createUser(data: { username:    string; email: string; password: string }) 
{
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
return await response.json();
}

fetch to send an item

This example uses the fetch API to send a new item to the server. headers specifies that the request body is JSON data. body contains the actual user data to send in the request. data is converted to a JSON string with JSON.stringify(). The JSON string is sent to the server in the body of the request.

const onSubmit = async (e: React.FormEvent>) => {
e.preventDefault();

try {
const response = await fetch('/api/items', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(item),
});

if (!response.ok) {throw new Error('ERROR');}

setItem({
owner: 0,
title: '',
description: '',
url: '',
});

router.push('/');
} catch (error) {
console.error('Error in CreateItem!', error);
}
};

fetch to retrieve users

This example uses the fetch API to request the list of users at endpoint /api/users. The asynchronous fetch call makes a GET request which returns a response object on resolve.

async function getUsers() { 
const response = await fetch('/api/users',
{
method: 'GET',
});
return await response.json();
}

status code

The response object contains contains the status code:

  • 200 - success
  • 404 - not found
  • 500 - server error

Using the fetch API, the response.ok property is a boolean that indicates whether the HTTP response was successful. response.ok will be true if the response status code is 200.

async function getUsers() { 
const response = await fetch('/api/users',
{
method: 'GET',
});

if (!response.ok) {
throw new Error('Failed to fetch users');
}

return await response.json();
}

fetch to load items on mount

This example uses the fetch API to request the list of items at endpoint /api/items. The asynchronous fetch call makes a GET request which returns a response object on resolve. useEffect() ensures this fetch runs when the component mounts.

export default function ShowItemList() {
const [items, setItems] = useState([]);

useEffect(() => {
const fetchItems = async () => {
try {
const response = await fetch('/api/items');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setItems(data.items);
} catch (error) {
console.log('Error from ShowItemList:', error);
}
};
fetchItems();
}, []);

fetch a specific item

This example uses the fetch API to request a specific item at endpoint /api/items/[id]. The useEffect() hook makes the HTTP request when the component mounts. This is helpful when we don't have a user event, such as a button click to trigger the request. The asynchronous fetch call makes a GET request which returns a response object on resolve.

'use client';

import { useState, useEffect } from 'react';

type Item = {
title: string;
description: string;
published_date: string;
image: string;
};

export default async function ShowItem({ params }: {params: Promise<{ id: string }>}) {
const { id } = await params;

const [item, setItem] = useState<Item>({
title: '',
description: '',
published_date: '',
image: '',
});

useEffect(() => {
const fetchItem = async () => {
try {
const response = await fetch(`/api/items/${id}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
const itemData = data.item;

setItem({
title: itemData.title || '',
description: itemData.description || '',
published_date: itemData.published_date || '',
image: itemData.image || '',
});
} catch (error) {
console.error('Error from ShowItem:', error);
}
};

if (id) fetchItem();
}, [id]);

return (
<div className="max-w-2xl mx-auto mt-10 p-4 border rounded shadow">
<h1 className="text-2xl font-semibold mb-2">{item.title}</h1>
<p className="mb-4">{item.description}</p>
<p className="text-sm text-gray-600 mb-4">
Published: {item.published_date}
</p>
{item.image && (
<img src={item.image} alt={item.title} className="w-full rounded" />
)}
</div>
);
}


fetch data from an external api

quote of the day with fetch()
async function getWeather(city) {
const apiKey = "API_KEY";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`;

try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
console.log(`Weather in ${city}: ${data.weather[0].description}`);
} catch (err) {
console.error("Fetch error:", err);
}
}
getWeather("Athens");

http codes

HTTP status codes

HTTP status codes are three-digit numbers that indicate the outcome of a client request, such as a browser requesting a webpage. These codes are categorized into five main groups (1xx, 2xx, 3xx, 4xx, 5xx), each signifying different results. For example:

  • 200 Success
  • 404 Requested resource could not be found.