How to consume a RESTful API in React
You will need npm installed, and a basic knowledge of React.
How to consume a RESTful API in React
This brief tutorial will help you understand the concepts necessary for integrating a RESTful API into a React application.
React is still one of the most popular frontend frameworks out there in 2022, so knowing the various ways of integrating a RESTful API is a necessary skill for any frontend developer.
For this tutorial, we will build a simple contact list application to display a list of contacts’ names, emails, and tagline. Here’s what we’re going to do:
- Fetch some data from an endpoint
- Save the data in the state
- Render said data
By the end of this tutorial, you will know how to consume a REST API in React using multiple methods.
Prerequisites
To follow along, you need the following:
- Basic knowledge of React (versions > 16)
- Basic understanding of what an API is
- NPM installed on your computer
Set up our environment
There are multiple ways to start a React project but to keep things simple, I’ve gone ahead and set up a simple template that you can clone to get started.
- Clone the ready-made React template and change it into the new directory.
git clone https://github.com/pusher/react-rest-api-tutorial.git
cd react-rest-api-tutorial
- Install all dependencies.
npm install
- Start the application.
npm run dev
By now, you should have an instance of the app running on your local machine on port 5173. The template itself is fairly simple. It uses Vite, which is a build tool that aims to provide a fast and lean development experience for web projects.
You can explore other ways to start a new React project.
Take some time to look through the project and you’ll see a bunch of ready-made files and components.
For the sake of this tutorial, the only files that matter are:
- main.jsx — The entry point of the app.
- App.jsx — The main container of the app. Holds all other components.
- Contact.jsx — Renders the details of a single contact.
With that out of the way, we can continue with actually consuming a REST API and rendering some data based on the response.
Consuming a REST API in React
As a quick refresher, a REST API is an API that maps a resource to an endpoint. Resource, in this case, means any piece of data necessary for an application to function. For example, a list of contacts resource(s) could be mapped to a /contacts
endpoint.
To learn more about REST APIs, IBM has a good resource on it.
With that out of the way, the first thing we need to do is determine which API we’ll be consuming.
To avoid having to set up a whole server just for this tutorial, we’ll be consuming dummy data from a free, public API created for just this purpose, JSONPlaceholder.
It exposes a bunch of useful common endpoints and we’ll be consuming the /users
endpoint that looks like https://jsonplaceholder.typicode.com/users
.
Now that we have an endpoint, we have to determine how to actually consume it in our React app. There are multiple options available to choose from when it comes to making an API request in a React app:
-
Fetch/Axios – The easiest option is to use the Fetch API or use a library like Axios to make API requests. These are pretty bare-bones options without any advanced functionality like caching, deduping requests, etc.
-
SWR/React Query – For complex applications that require a more robust solution, it’s probably a better idea to go with a full-fledged data fetching library which offers a lot more functionalities out of the box.
We’ll explore both options below.
Using Fetch and Axios
Fetch API is a web standard that is implemented in all major browsers to allow for making network requests in a standardized way.
Axios is a third-party library that is functionally very similar to Fetch. It offers a few improvements over Fetch such as better backward compatibility, data transforms, or the ability to intercept a request before or after it is made.
For the reasons listed above, I’ll be using Axios in this tutorial but save for some minor differences (e.g., Axios serializes the response into JSON automatically) in usage, you should be able to use Fetch in almost exactly the same way.
- Install the Axios library. Fetch doesn’t need to be installed as it ships with every major browser save for Internet Explorer.
npm install axios
- Open the
App.jsx
file and import the Axios library as well as some React hooks:
import { useState, useEffect } from 'react'
import axios from 'axios'
import Contact from './Contact'
// continues below (1)
- We need to store the response (or error, if any) from calling the API in React state. Initialize two state variables:
// continues from above (1)
function App() {
const [contacts, setContacts] = useState([]);
const [error, setError] = useState(null);
// continues below (2)
- We need to query the REST API endpoint when the
App
component is mounted and for that, we’ll use theuseEffect
hook:
// continues from above (2)
useEffect(() => {
axios("https://jsonplaceholder.typicode.com/users")
.then((response) => {
setContacts(response.data);
setError(null);
})
.catch(setError);
/* Using Fetch
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((response) => {
setContacts(response);
setError(null);
})
.catch(setError);
*/
}, []);
// continues below (3)
- Finally, we can render the data fetched from the
/users
endpoint. First, we check if there are any errors before rendering and then loop over the list of contacts in the state. For each contact, we will render one instance of the<Contact />
component:
// continues from above (3)
if (error) return <p>An error occurred</p>
return (
<div className="App">
{contacts.map(({ id, name, email, company }) => (
<Contact
key={id}
name={name}
email={email}
tagline={company.catchPhrase}
/>
))}
</div>
);
}
export default App;
To recap, here’s what we’ve done:
- Installed the
Axios
library. - Imported it in our
App.jsx
file as well as theuseState
anduseEffect
React hooks. - When the component mounted, we made a network request to
https://jsonplaceholder.typicode.com/users
to fetch a list of people and saved the response in the state. - Check for an error before rendering the list of people in state. If there’s an error, we render an error message.
- Otherwise, we loop through the list of people in the state and render a
<Contact />
component for each of them.
Check out a snapshot of how your code should look at this point.
Using SWR
The next option, SWR, is a more robust library that offers a ton of features for more advanced use cases. It integrates nicely with React Suspense, offers in-built pagination features, and caches data automatically, among a host of other useful features.
NOTE: This tutorial uses version 1.3 of SWR.
Using it is relatively simple as we’ll see shortly.
- Install the SWR library like so —
npm install swr
- Import the
useSWR
custom hook that allows us to manage our API requests —
import useSWR from 'swr'
import Contact from './Contact'
// continues below (1)
- SWR requires that we create a helper “fetcher” function that will query the endpoint for us. We will use Fetch in this function but according to the SWR docs, you can also use Axios or a GraphQL library:
// continues from above (1)
const fetcher = (...args) => fetch(...args).then((res) => res.json());
// continues below (2)
- Now that we have the plumbing set up, we can go ahead and consume the API.
// continues from above (2)
function App() {
const { data, error } = useSWR(
"https://jsonplaceholder.typicode.com/users",
fetcher
);
// continues below (3)
- Render the data from the endpoint when it becomes available.
// continues from above (3)
if (error) return <p>An error occurred</p>;
if (!data) return <p>Loading</p>;
return (
<div className="App">
{data.map(({ id, name, email, company }) => (
<Contact
key={id}
name={name}
email={email}
tagline={company.catchPhrase}
/>
))}
</div>
);
}
export default App;
As you can see, using SWR is simple thanks to the very well-designed useSWR
hook. There are some notable differences from the Fetch/Axios method above, notably:
- SWR provides a custom hook,
useSWR
so we don’t have to bring inuseState
anduseEffect
- Error handling and loading state is handled for us
To explore their other capabilities, check out SWR docs.
Check out a snapshot of how your code should look like at this point.
Using React Query
The final option we’ll be exploring is React Query. It aims to be an opinionated way of fetching/updating data in React. And as a result, comes with a ton of useful features like parallel queries, pausing queries, automatic retries, etc.
NOTE: This tutorial uses version 4 of React Query.
Using it is slightly more complicated than the options above but is thankfully relatively still simple.
- Install the React Query library
npm i @tanstack/react-query
- We have to wrap the app in a “QueryClientProvider” which will make it possible to query endpoints from any component. Open the
src/main.jsx
file and wrap theApp
component like so:
import React from "react";
import ReactDOM from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App";
import "./index.css";
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);
- With the QueryClientProvider set up, we can now query endpoints in our
App
component. Open thesrc/App.jsx
file and import theuseQuery
custom hook:
import { useQuery } from '@tanstack/react-query'
import Contact from "./Contact";
// continues below (1)
- Just like with SWR, we need a “fetcher” method that will
actuallymake the request for us. Again, we will use Fetch but feel free to substitute with Axios or any other data fetching library:
// continues from above (1)
const fetcher = () =>
fetch("https://jsonplaceholder.typicode.com/users").then((res) =>res.json())
// continues below (2)
- With the fetcher set up, we can now go ahead and consume the endpoint:
// continues from above (2)
function App() {
const { isLoading, error, data } = useQuery(["contacts"], fetcher);
// continues below (3)
Notice the first argument we pass to useQuery
is an array containing "``contacts``"
. This is a unique identifier for this request so React Query knows how to differentiate it from other requests. This is necessary for some of the more advanced features like caching, pausing requests, etc.
- Finally, we can then render our data from the endpoint:
// continues from above (3)
if (isLoading) return <p>Loading</p>;
if (error) return <p>An error occurred</p>;
return (
<div className="App">
{data.map(({ id, name, email, company }) => (
<Contact
key={id}
name={name}
email={email}
tagline={company.catchPhrase}
/>
))}
</div>
);
}
export default App;
To explore their other capabilities, check out React Query docs.
Check out a snapshot of how your code should look at this point.
Conclusion
We’ve explored four ways of consuming an API in React. This is just the iceberg as there are a lot of things to consider when fetching data in a frontend application.
You can take this further by implementing a proper loading state, better error handling, caching data, etc.
Hopefully, this tutorial was useful and if you run into any issues following along or if you think this tutorial could be improved, please submit an issue.
13 September 2022
by Fisayo Afolayan, Ovie Okeh