API Routes in Next.js: Building a Full-Stack Application
Leverage API Routes to Create a Comprehensive Full-Stack Application
Next.js is not just a front-end framework; it also allows you to build powerful full-stack applications with its integrated API routes. This feature enables you to define backend endpoints directly within your Next.js project, providing a seamless way to handle server-side logic, data fetching, and integrations. In this blog, we'll explore how to use API routes in Next.js and build a full-stack application.
What are API Routes?
API routes in Next.js allow you to create serverless functions as part of your application. These routes can handle HTTP requests and are defined within the pages/api
directory. Each file in this directory maps to an endpoint in your application.
Benefits of API Routes
Unified Project Structure:
- Keep your backend and frontend code in a single project, simplifying development and deployment.
Serverless Architecture:
- API routes are serverless functions that scale automatically and reduce infrastructure management.
Flexibility:
- Handle various tasks like form submissions, database operations, authentication, and third-party API integrations.
Building a Full-Stack Application
Let's build a simple full-stack application with Next.js. We'll create a task management app with the following features:
A form to add new tasks.
A list of tasks fetched from an API route.
The ability to delete tasks.
Step 1: Setting Up Your Project
Ensure you have a Next.js project set up. If not, create a new one:
npx create-next-app task-manager
cd task-manager
Step 2: Creating the API Routes
We'll create API routes for managing tasks. First, let's create a mock database using an array.
Create a Mock Database
Create a new file called
data.js
in the root directory:// data.js let tasks = []; export const getTasks = () => tasks; export const addTask = (task) => { tasks.push(task); }; export const deleteTask = (id) => { tasks = tasks.filter(task => task.id !== id); };
Create the Tasks API
Create a new file called
pages/api/tasks.js
:// pages/api/tasks.js import { getTasks, addTask, deleteTask } from '../../data'; export default function handler(req, res) { if (req.method === 'GET') { // Return all tasks const tasks = getTasks(); res.status(200).json(tasks); } else if (req.method === 'POST') { // Add a new task const task = req.body; addTask(task); res.status(201).json(task); } else if (req.method === 'DELETE') { // Delete a task const { id } = req.body; deleteTask(id); res.status(204).end(); } else { res.setHeader('Allow', ['GET', 'POST', 'DELETE']); res.status(405).end(`Method ${req.method} Not Allowed`); } }
Step 3: Creating the Frontend
Create the Task Form
Create a new file called
components/TaskForm.js
:// components/TaskForm.js import { useState } from 'react'; const TaskForm = ({ onAddTask }) => { const [task, setTask] = useState(''); const handleSubmit = async (e) => { e.preventDefault(); if (task.trim()) { const newTask = { id: Date.now(), task }; await fetch('/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(newTask), }); onAddTask(newTask); setTask(''); } }; return ( <form onSubmit={handleSubmit}> <input type="text" value={task} onChange={(e) => setTask(e.target.value)} placeholder="Add a new task" required /> <button type="submit">Add Task</button> </form> ); }; export default TaskForm;
Create the Task List
Create a new file called
components/TaskList.js
:// components/TaskList.js const TaskList = ({ tasks, onDeleteTask }) => { const handleDelete = async (id) => { await fetch('/api/tasks', { method: 'DELETE', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id }), }); onDeleteTask(id); }; return ( <ul> {tasks.map((task) => ( <li key={task.id}> {task.task} <button onClick={() => handleDelete(task.id)}>Delete</button> </li> ))} </ul> ); }; export default TaskList;
Create the Main Page
Modify
pages/index.js
to include the task form and task list components:// pages/index.js import { useState, useEffect } from 'react'; import TaskForm from '../components/TaskForm'; import TaskList from '../components/TaskList'; export default function Home() { const [tasks, setTasks] = useState([]); useEffect(() => { const fetchTasks = async () => { const res = await fetch('/api/tasks'); const tasks = await res.json(); setTasks(tasks); }; fetchTasks(); }, []); const addTask = (task) => { setTasks([...tasks, task]); }; const deleteTask = (id) => { setTasks(tasks.filter(task => task.id !== id)); }; return ( <div> <h1>Task Manager</h1> <TaskForm onAddTask={addTask} /> <TaskList tasks={tasks} onDeleteTask={deleteTask} /> </div> ); }
Step 4: Run the Development Server
Start the development server:
npm run dev
Conclusion
Explore the official Next.js documentation on API routes to learn more about advanced features and best practices. Happy coding!