# API Routes in Next.js: Building a Full-Stack Application

[Next.js](https://bytescrum.com/) 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](https://nextjs.org/docs/pages/building-your-application/routing/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

1. **Unified Project Structure:**
    
    * Keep your backend and frontend code in a single project, simplifying development and deployment.
        
2. **Serverless Architecture:**
    
    * API routes are serverless functions that scale automatically and reduce infrastructure management.
        
3. **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](https://blog.bytescrum.com/how-to-build-your-first-nextjs-app-step-by-step-tutorial) project set up. If not, create a new one:

```bash
npx create-next-app task-manager
cd task-manager
```

### Step 2: Creating the API Routes

We'll create [API routes](https://blog.bytescrum.com/nextjs-dynamic-routes-nested-routes-with-folder-structure) for managing tasks. First, let's create a mock database using an array.

1. **Create a Mock Database**
    
    Create a new file called `data.js` in the root directory:
    
    ```javascript
    // 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);
    };
    ```
    
2. **Create the Tasks API**
    
    Create a new file called `pages/api/tasks.js`:
    
    ```javascript
    // 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

1. **Create the Task Form**
    
    Create a new file called `components/TaskForm.js`:
    
    ```javascript
    // 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;
    ```
    
2. **Create the Task List**
    
    Create a new file called `components/TaskList.js`:
    
    ```javascript
    // 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;
    ```
    
3. **Create the Main Page**
    
    Modify `pages/index.js` to include the task form and task list components:
    
    ```javascript
    // 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:

```bash
npm run dev
```

<details data-node-type="hn-details-summary"><summary>Conclusion</summary><div data-type="detailsContent">By using API routes in Next.js, you can create a comprehensive full-stack application with a unified project structure. This approach simplifies development and deployment, providing a seamless way to handle both frontend and backend logic. Next.js’s API routes enable you to build scalable and efficient serverless functions, making it an excellent choice for modern web applications.</div></details>

Explore the official Next.js [documentation](https://nextjs.org/docs) on API routes to learn more about advanced features and best practices. Happy coding!
