DEV Community

Cover image for Simplest guide to Next.js APIs
Code With Joseph
Code With Joseph

Posted on

Simplest guide to Next.js APIs

What Makes Next.js APIs So Special?

I'm assuming you know what APIs are. APIs are an important part of developing functional web apps. Next.js has introduced the feature to create route handlers for APIs since version 9.0 in 2019. There are lots of ways to build a separate backend (like Ruby, PHP, Express.js, Django, etc.) other than Next.js, so why even do it in Next.js?.

It might not be that great

By default, Next.js route handlers use serverless functions, which means in some cases you might have cold starts, high cost for scaling, and vendor lock-in since it requires serverless platforms like Vercel to work properly. It also has limitations when it comes to using complex middleware, unlike a library like Express.js, which was meant to be used for routing on a server.

But it's not that bad

But most of these issues are automatically taken care of by Vercel (which provides amazing caching & optimization strategies) and serverless functions can be scalable and cost-effective if done properly. Here are some more benefits of using Next.js as both your frontend and backend:

  • Hot reloading: This means when developing, you get the same hot reload features as your frontend for your API routes, which makes development faster.
  • Consistency of your codebase: It greatly simplifies development by keeping the frontend and backend logic in the same place.
  • File-based routing: API routes use a simple file-based routing system that easily integrates into your Next.js project structure.
  • No additional setup: There's no need to configure additional middleware or create a separate server.
  • Simplication: It has built-in features to simplify common tasks when developing your API.

API routes in the Next.js app router

The app router uses a file-based routing system that starts from the app directory. You can mirror URL paths by defining API routes in a nested folder structure. By doing this, you create Node.js serverless functions that act as API endpoints.

app/
└── api/
    └── hello/
        └── route.js
Enter fullscreen mode Exit fullscreen mode

Creating API routes

The API route file is usually named route.js or route.ts (for TypeScript users). This has to be in an api folder in the app folder. You can define functions in the route.js files that handle different HTTP methods (such as GET, POST, PUT, PATCH, etc.). For example, when you can make a GET request to /api/hello it would be handled by a GET function in app/api/hello/route.js.

Request methods and API route functions

The standard convention is that within the route.js or route.ts file, you name an exported function with the HTTP method you want it to handle in your API endpoint in uppercase. The functions usually look like this:

// app/api/users/route.js

export async function GET(request) {
  // Simulate a database call to fetch users
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' },
  ];

  // Return the users as a JSON response
  return NextResponse.json(users);
}

Enter fullscreen mode Exit fullscreen mode

NextResponse and Request

The NextResponse is a helper class that extends the web Response API with additional convenience methods, which are used to create responses. You can use it to rewrite, redirect, set headers, or create and send JSON responses.


The Request: When you define functions by using HTTP methods in creating your API endpoints, the functions receive a Request object as an argument which contains information about the incoming request. The object uses the web Request API. You can use it to read the request query parameters, read the request body, or access the request headers.

Dynamic routes

By using square brackets, when naming your folders before the route.ts or route.js file, you can create a dynamic route for your API.

app/
  └── api/
      └── users/
          └── [userId]/
              └── route.ts
Enter fullscreen mode Exit fullscreen mode

Accessing a dynamic route

The dynamic route parameters can be accessed from the route handler function's second argument, which has the params object.
Take a look at this example:

// app/api/users/[userId]/route.ts

export async function GET(request: Request, { params }: { params: { userId: string }}) {
const {userId} = params

  // Simulate a database call to fetch users
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' },
  ];

  //filter user by id
  const user = users.filter((user) => user.id == userId)

  // Return the users as a JSON response
  return NextResponse.json(user);
}
Enter fullscreen mode Exit fullscreen mode

I hope that wasn't complicated, and you got something out of this.
You can hear more from me on:
Twitter (X) | Instagram

Top comments (0)