In modern web development, integrating REST APIs into React applications is a crucial skill. REST (Representational State Transfer) is an architectural style for designing networked applications. It allows communication between a client (in this case, React) and a server by making HTTP requests to specific endpoints and receiving responses, typically in JSON format.
A REST API provides a set of functions (called endpoints) that allow developers to send requests and receive responses over HTTP. These APIs follow REST principles, including:
While GraphQL allows you to request specific data fields, REST follows a resource-based approach. REST uses HTTP methods like GET (read), POST (create), PUT (update), and DELETE (remove) for interacting with resources.
To get started with React and REST APIs, first, create a new React app using create-react-app
if you don’t already have one.
npx create-react-app react-rest-api
cd react-rest-api
npm start
This will initialize a React project and start the development server at http://localhost:3000.
The Fetch API is a modern, built-in JavaScript API for making HTTP requests. It is widely used to interact with REST APIs in React.
Let’s start with a basic GET request to fetch data from a REST API using the fetch()
function.
import React, { useEffect, useState } from 'react';
const UsersList = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users') // Sample REST API
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
})
.catch((error) => console.error('Error fetching data:', error));
}, []);
if (loading) return Loading...
;
return (
{users.map((user) => (
-
{user.name} - {user.email}
))}
);
};
export default UsersList;
fetch()
: The fetch()
function makes an HTTP GET request to the API. In this case, we are fetching a list of users from jsonplaceholder.typicode.com
, a fake REST API..then()
: The promise returned by fetch()
is resolved with a response object. We then use .json()
to parse the response into JSON format.useState
and useEffect
are used to manage the state of the component, where users
stores the fetched data, and loading
keeps track of the loading state.The component fetches a list of users from the API and renders them in an unordered list. If the data is still being fetched, it displays a loading message.
To create new resources on a server, we can use a POST request. Let’s modify the previous example by adding a form to create a new user.
import React, { useState } from 'react';
const AddUserForm = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, email }),
})
.then((response) => response.json())
.then((data) => console.log('User created:', data))
.catch((error) => console.error('Error creating user:', error));
};
return (
);
};
export default AddUserForm;
name
and email
in the request body.Content-Type
header to application/json
because we are sending JSON data.JSON.stringify()
: This method is used to convert the JavaScript object { name, email }
into a JSON string for the request body.This form allows users to submit their name and email. When the form is submitted, the user’s data is sent to the API, and a new user is created. In a real-world scenario, you would likely update the UI after the user is added.
A PUT request is used to update an existing resource. Let’s modify the code to update a user’s information.
const updateUser = (id, updatedName) => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: updatedName }),
})
.then((response) => response.json())
.then((data) => console.log('User updated:', data))
.catch((error) => console.error('Error updating user:', error));
};
PUT
method is used to update the user with a specific ID (${id}
). We send the updated data in the request body using JSON.stringify()
.The DELETE
method is used to remove a resource from the server.
const deleteUser = (id) => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'DELETE',
})
.then((response) => {
if (response.ok) {
console.log('User deleted');
}
})
.catch((error) => console.error('Error deleting user:', error));
};
DELETE
method removes the user with the specified ID from the server.These functions allow us to update and delete users in our app by sending PUT and DELETE requests to the API.
Axios is a popular HTTP client library that simplifies API requests. It provides a cleaner and more intuitive syntax than fetch()
, supports automatic JSON data transformation, and handles errors more consistently.
To use Axios, install it in your project.
npm install axios
Let’s rewrite the previous GET request using Axios.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const UsersList = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
axios
.get('https://jsonplaceholder.typicode.com/users')
.then((response) => {
setUsers(response.data);
setLoading(false);
})
.catch((error) => console.error('Error fetching data:', error));
}, []);
if (loading) return Loading...
;
return (
{users.map((user) => (
-
{user.name} - {user.email}
))}
);
};
export default UsersList;
axios.get()
: Axios simplifies GET requests with a single method call. The response is automatically parsed, and the data
is available in response.data
.The Axios version provides the same functionality as the Fetch version but with a simpler syntax and automatic handling of JSON conversion.
Handling errors is crucial when dealing with APIs. We can handle errors at different levels in both Fetch and Axios.
In fetch()
, errors can be caught using .catch()
. However, fetch only rejects a promise if there’s a network failure. To handle API errors (like 404 or 500 status codes), you need to check response.ok
.
fetch('https://jsonplaceholder.typicode.com/users/12345')
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.catch((error) => console.error('Error:', error));
In Axios, any response with a status code outside the 200 range will automatically trigger the catch()
block.
axios
.get('https://jsonplaceholder.typicode.com/users/12345')
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.error('Error fetching data:', error.response);
});
Sometimes, API requests are triggered too frequently (e.g., on every keypress in a search input). This can be optimized by debouncing the requests.
import React, { useState } from 'react';
import axios from 'axios';
import debounce from 'lodash.debounce';
const SearchUsers = () => {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const fetchUsers = debounce((query) => {
axios.get(`https://jsonplaceholder.typicode.com/users?name=${query}`)
.then(response => setResults(response.data));
}, 500);
const handleInputChange = (e) => {
setQuery(e.target.value);
fetchUsers(e.target.value);
};
return (
{results.map(user => (
- {user.name}
))}
);
};
debounce
function from Lodash delays the API request until the user has stopped typing for 500 milliseconds. This reduces the number of requests made to the API.We explored how to use REST APIs in React applications. We covered how to make requests using the Fetch API and Axios, how to handle HTTP methods like GET, POST, PUT, and DELETE, and how to manage errors. We also discussed optimization techniques like debouncing. By now, you should be comfortable with integrating REST APIs into your React projects, fetching and sending data, and handling responses effectively. Happy Coding!❤️