Mastering Next.js 13/14 : App Router and API Routes
Tags: javascript, nextjs, react, typescript
Published: 2024-04-19 00:04:31

Next.js 13 introduced a new routing system called the App Router, which provides a more flexible and intuitive way to define routes and handle navigation in your application.

#### What is the App Router ?

The App Router is built on top of React Server Components and introduces new concepts and conventions for defining routes and handling navigation.

With the App Router, you define your routes using a directory structure inside the `app` directory. Each directory represents a route segment, and the files inside those directories define the UI and behavior for that route.

Here's an example of a basic App Router structure:

```
app/
  dashboard/
    layout.js
    page.js
  settings/
    layout.js
    page.js
  layout.js
  page.js
```

In this example, we have two routes: `/dashboard` and `/settings`. Each route has its own `layout.js` and `page.js` files. The `layout.js` file defines the common UI layout for that route, while the `page.js` file defines the specific UI for that route.

#### Migrating from Pages Router to App Router

If you have an existing Next.js application using the Pages Router, you can migrate to the App Router incrementally. The App Router is available in Next.js 13 and later versions and can coexist with the Pages Router.

To start migrating, you can create an `app` directory at the root of your project and gradually move your routes and components into it. You can have a mix of Pages Router and App Router in your application during the migration process.

Here's an example of a migrated route:

Before :
```
pages/
  dashboard.js
```

After :
```
app/
  dashboard/
    page.js
```

In this example, the `/dashboard` route is migrated to the App Router by creating a `dashboard` directory inside the `app` directory and moving the route's logic into the `page.js` file.

#### File-based Routing

With the App Router, routes are defined using a file-based convention. Each file inside the `app` directory represents a route segment, and the directory structure determines theroute hierarchy.

Here's an example of a more complex App Router structure:

```
app/
  blog/
    [slug]/
      page.js
    page.js
  dashboard/
    settings/
      page.js
    page.js
  layout.js
  page.js
```

In this example, we have the following routes:

- `/`: Defined by `app/page.js`
- `/blog`: Defined by `app/blog/page.js`
- `/blog/[slug]`: Defined by `app/blog/[slug]/page.js`, where `[slug]` is a dynamic segment
- `/dashboard`: Defined by `app/dashboard/page.js`
- `/dashboard/settings`: Defined by `app/dashboard/settings/page.js`

The `layout.js` file at the root level defines the common UI layout for all routes.

#### Layouts and Nesting

The App Router introduces the concept of layouts, which allow you to define shared UI across multiple routes. Layouts are defined using the `layout.js` file in each route directory.

Here's an example of a layout file:

```jsx
// app/dashboard/layout.js
import Sidebar from './Sidebar';

export default function DashboardLayout({ children }) {
  return (
    <div>
      <Sidebar />
      <main>{children}</main>
    </div>
  );
}
```

In this example, the `DashboardLayout` component defines the common UI structure for all routes within the `/dashboard` route. The `children` prop represents the content of the nested routes.

Layouts can be nested, allowing you to create a hierarchy of shared UI components. For example:

```
app/
  dashboard/
    settings/
      page.js
    layout.js
    page.js
  layout.js
```

In this case, the `app/dashboard/layout.js` file defines the layout for the `/dashboard` route, and the `app/layout.js` file defines the root layout for all routes.

#### Data Fetching with the App Router

The App Router provides a new data fetching approach using React Server Components. You can fetch data directly in your components using the `fetch` function or other data fetching libraries.

Here's an example of data fetching in a page component:

```jsx
// app/blog/[slug]/page.js
async function getPost(slug) {
  const res = await fetch(`https://api.example.com/posts/${slug}`);
  return res.json();
}

export default async function PostPage({ params }) {
  const post = await getPost(params.slug);

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}
```

In this example, the `getPost` function fetches a blog post from an API based on the `slug` parameter. The `PostPage` component is an async function that awaits the data fetching and renders the post.

The App Router automatically handles data fetching on the server and sends the pre-rendered HTML to the client, providing a fast initial load experience.

### 6. API Routes

Next.js allows you to create API routes, which are server-side endpoints that can handle HTTP requests and perform server-side logic.

#### Creating API Routes

To create an API route, you need to create a file inside the `pages/api` directory. The file name becomes the route path, and the default export is a request handler function.

Here's an example of a simple API route:

```jsx
// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello, World!' });
}
```

In this example, the `/api/hello` route responds with a JSON object containing a "Hello, World!" message.

#### Handling HTTP Methods

API routes can handle different HTTP methods like GET, POST, PUT, DELETE, etc. You can use conditional statements based on the `req.method` to handle specific methods.

Here's an example:

```jsx
// pages/api/users.js
export default function handler(req, res) {
  if (req.method === 'GET') {
    // Handle GET request
    res.status(200).json({ users: [] });
  } else if (req.method === 'POST') {
    // Handle POST request
    const newUser = req.body;
    // Process the new user data
    res.status(201).json({ message: 'User created' });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
}
```

In this example, the `/api/users` route handles GET and POST requests differently. It returns a list of users for GET requests and creates a new user for POST requests.

#### Connecting to Databases

API routes can connect to databases or external services to perform data operations. You can use libraries like `prisma`, `mongoose`, or any other database client to interact with your database.

Here's an example using Prisma:

```jsx
// pages/api/posts.js
import prisma from '../../lib/prisma';

export default async function handler(req, res) {
  if (req.method === 'GET') {
    const posts = await prisma.post.findMany();
    res.status(200).json({ posts });
  } else if (req.method === 'POST') {
    const { title, content } = req.body;
    const newPost = await prisma.post.create({
      data: {
        title,
        content,
      },
    });
    res.status(201).json({ post: newPost });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
}
```

In this example, the `/api/posts` route uses Prisma to fetch posts from a database for GET requests and create a new post for POST requests.

#### Authentication and Authorization

API routes can handle authentication and authorization to protect sensitive data or restrict access to certain endpoints. You can use libraries like `jsonwebtoken` or `next-auth` to implement authentication strategies.

Here's an example using `jsonwebtoken`:

```jsx
// pages/api/protected.js
import jwt from 'jsonwebtoken';

const secretKey = process.env.JWT_SECRET;

export default function handler(req, res) {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    res.status(401).json({ message: 'Unauthorized' });
    return;
  }

  try {
    const decoded = jwt.verify(token, secretKey);
    // Access the authenticated user data from `decoded`
    res.status(200).json({ message: 'Protected data' });
  } catch (error) {
    res.status(401).json({ message: 'Invalid token' });
  }
}
```

In this example, the `/api/protected` route checks for the presence of a JWT token in the `Authorization` header. It verifies the token using the secret key and grants access to protected data if the token is valid.

Let's go for Part 3 : Deployment and Advanced techniques !

- NextJS Advanced Techniques : https://dev.to/fabrikapp/mastering-nextjs-1314-advanced-techniques-5ba

Or go back to your fundamentals :
- NextJS Fundamentals : https://dev.to/fabrikapp/mastering-nextjs-1314-building-dynamic-web-applications-part-1-fundamentals-gh1