How to Build and Consume an API in Next.js
Gone are the days when you had to create a separate backend for your website. With Next.js file-based API routing, you can make life easier by writing your API in a Next.js project.
Next.js is a React meta framework with features that simplify the process of building production-ready web apps. You will see how to create a REST API in Next.js and use that API’s data in a Next.js page.
Create a Next.js project with create-next-app
You can create a new Next.js project using the create-next-app CLI tool. It installs the necessary packages and files so you can start building a Next.js application.
Run this command in a terminal to create a new Next.js folder called api-routes. You may get a prompt to install create-next-app.
npx create-next-app api-routes
When the command is complete, open the api-routes folder to start creating the API routes.
API routing in Next.js
API routes run on the server and have many uses, such as: For example, storing user data in a database or retrieving data from an API without throwing the CORS policy error.
In Next.js you need to create API routes in the /pages/api folder. Next.js generates API endpoints for each of the files in this folder. When you add user.js to /pages/api, Next.js creates an endpoint at http://localhost:3000/api/user.
A basic Next.js API route has the following syntax.
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
You must export the handler function for it to work.
Creating API routes
Create a new file named todo.js in the /pages/API Folder to add an API route for tasks.
Mocking the todo database
To get the todos you need to create a GET endpoint. For the sake of simplicity. This tutorial uses a set of todo items instead of a database, but you’re welcome to use a database like MongoDB or MySQL.
Create the todo items in todo.js in the root folder of your application and then add the following data.
export const todos = [
{
id: 1,
todo: "Do something nice for someone I care about",
completed: true,
userId: 26,
},
{
id: 2,
todo: "Memorize the fifty states and their capitals",
completed: false,
userId: 48,
},
];
These ToDo items come from the DummyJSON website, a REST API for dummy data. You can find the exact dates from this DummyJSON Todos endpoint.
Next, create the API route in /pages/api/todos.js and add the handler function.
import { todos } from "../../todo";export function handler(req, res) {
const { method } = req;
switch (method) {
case "GET":
res.status(200).json(todos);
break;
case "POST":
const { todo, completed } = req.body;
todos.push({
id: todos.length + 1,
todo,
completed,
});
res.status(200).json(todos);
break;
default:
res.setHeader("Allow", ["GET", "POST"]);
res.status(405).end(`Method ${method} Not Allowed`);
break;
}
}
This route handles the GET and POST endpoints. It returns all todos for the GET request and adds a todo item to the todo database for a POST request. For other methods, the handler returns an error.
Consuming API routes in the frontend
You’ve created an API endpoint that returns a JSON object containing an array of tasks.
To consume the API, create a function called fetchTodos that retrieves data from the API endpoint. The function uses the Fetch method, but you can also use Axios to make API requests. Then call that function when you click a button.
import Head from "next/head";
import { useState } from "react"; export default function Home() {
const [todos, settodos] = useState([]);
const fetchTodos = async () => {
const response = await fetch("/api/todos");
const data = await response.json();
settodos(data);
};
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<button onClick={fetchTodos}>Get todos</button>
<ul>
{todos.map((todo) => {
return (
<li
style={{ color: `${todo.completed ? "green" : "red"}` }}
key={todo.id}
>
{todo.todo}:{todo.completed}.
</li>
);
})}
</ul>
</main>
</div>
);
}
The list in this snippet shows the todo items as they are retrieved.
For the POST endpoint, create a new function called saveTodo that sends a POST request to the API. The fetch request stores the new todo item in the body and returns all todo items including the new one. The saveTodo function then saves them in the todos state.
const saveTodo = async () => {
const response = await fetch("/api/todos", {
method: "POST",
body: JSON.stringify(newTodo),
headers: {
"Content-Type": "application/json",
},
});const data = await response.json();
settodos(data);
};
Then create a form with a text entry bar to receive the new task item. This form’s submit handler function calls the saveTodo function.
import Head from "next/head";
import { useReducer, useState } from "react";
import styles from "../styles/Home.module.css";export default function Home() {
const [todos, settodos] = useState([]);
const [newTodo, setnewTodo] = useState({
todo: "",
completed: false,
});
const fetchTodos = async () => {
};
const saveTodo = async (e) => {
const response = await fetch("/api/todos", {
method: "POST",
body: JSON.stringify(newTodo),
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
settodos(data);
};
const handleChange = (e) => {
setnewTodo({
todo: e.target.value,
});
};
const handleSubmit = (e) => {
e.preventDefault();
saveTodo();
setnewTodo({
todo: '',
});
};
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<button onClick={fetchTodos}>Get todos</button>
<form onSubmit={handleSubmit}>
<input type="text" onChange={handleChange} value={newTodo.todo} />
</form>
<ul>
{
</ul>
</main>
</div>
);
}
The handler adds a new task to the database each time a user submits the form. Also, this function updates the todos value using the data received from the API, which in turn adds the new todo item to the list.
API routing is just one of Next.js’ strengths
You saw how to create and use a Next.js API route. Now you can build a full-stack application without leaving your Next.js project folder. API routing is one of the many benefits Next.js offers.
Next.js also offers performance optimizations like code splitting, lazy loading, and built-in CSS support. If you are building a website that needs to be fast and SEO friendly, consider Next.js.