Search

Suggested keywords:
  • Java
  • Docker
  • Git
  • React
  • NextJs
  • Spring boot
  • Laravel

Next.js Route Handlers: Crafting Integrated API Endpoints

  • Share this:

post-title

Next.js is one of the popular React  frameworks, which streamlines the development process enabling developers to create a full-stack web application. One of its standout features is a highly flexible routing mechanism, allowing developers to seamlessly create and define API routes. An API route is essentially a URL that directs client requests to the specific server resource equipped to handle and process those requests.

Route Handlers are basically functions which are used to handle HTTP requests for a route and to send an appropriate response

Express.js or Next.js

This choice depend upon the type of application you are building,

Express.js is preferred  If we are building a server sided application its light-weight, flexible and fast, However if we are building a static site and SEO is our priority Next.js is preferred.

Migrating to Next13

In Next 13 we define route handlers in the route.js (route.ts in case of typescript) file in the app directory for any route segment unlike in Next 12 (page router) where you need to specify endpoints in a folder named  api.

Only catch is that we cannot define route.js and page.js at the same route segment level otherwise next.js gets confused whether we are trying to get the UI or access the endpoint.

Although it is not mandatory, we can follow the convention of defining route handlers in a folder named api. 

Route handlers allow custom request handler creation using the web Request and Response API. Next.js extends these native Request and Response with NextResponse and NextRequest to provide convenient helpers.

Setting up our application

Start by creating a new next application

npx create-next-app@latest

screenshot

After installation process create an api folder in the app directory, now all the route handler can be defined in a route.js file in this directory

screenshot

From the Route.js files we export the function with name corresponding to the HTTP methods (GET, POST etc)

Supported HTTP methods are

GET, POST, PUT, PATCH, DELETE, HEAD & OPTION

If an unsupported method is called, Next.js returns a 405 method not allowed response.

File: /app/api/route.js

export async function GET( request ) {
        //code
}

export async function POST( request ) {
        //code
}

export async function PUT( request ) {
        //code
}

export async function HEAD( request ){
        //code
}

export async function DELETE( request ) {
        //code
}

The parameter of these function consist of request and context

request object - This object is a NextRequest object, which is an extension web Request API, using which we get more control over the request including easily accessing cookies

context object- This object has only one value which is the params object (similar to params object in page.js and layout.js file) it contain all the dynamic route parameter for the given route

File: api/product/[productId]/route.js

export async function GET( request, context ) {

        const {id} = context.params;

       //Fetch from DB and return the response
}

Route Handlers can extend the Web Response API by returning a NextResponse object. This allows you to easily set cookies, headers, redirect, and rewrite

Static & Dynamic Route handler

Just the page.js file route handlers have also the option to be either statically executed or dynamically executed

 

Static route handler

By default all GET requests without a request object are statically executed, this means the file is executed once at the build time.

File: app/api/users/route.js

import { NextResponse } from "next/server";

export async function GET() {

  const res = await fetch("https://api.github.com/users");

  const data = await res.json();

  return NextResponse.json(data);

}

Now we can test the API using postman

screenshot

We can also revalidate the static fetches by passing the revalidate option in the fetch api or by manually exporting segment configuration option at the top of the file.

export const revalidate= 60

 

Dynamic route handler

Route handlers can be dynamically executed in cases of GET requests with request object, any other HTTP method, using cookies and headers or manually specifying the segment to dynamic mode.

File: app/api/users/[userId]/route.js

import { NextResponse } from "next/server";

export async function GET(request, context) {

  const { userId } = context.params;

  const res = await fetch("https://api.github.com/user/" + userId);

  const data = await res.json();

  return NextResponse.json(data);

}

screenshot

Note- These Route handlers have the same route segments configuration as page.js and layout.js

Search Query

Passing search parameter is a bit different, we create instance of URL and pass the url which returns us searchParams, using which we can extract the query strings

File: /app/api/idsearchquery/route.js

import { NextResponse } from "next/server";

export async function GET(request) {

  const { searchParams } = request.nextUrl;

  const id = searchParams.get("id");

  return NextResponse.json({ id });

}

 

screenshot

Redirect

We can redirect when a request is made, first import redirect function from ‘next/navigation’

File: /app/api/redirect/route.js

import { redirect } from "next/navigation";

export async function GET() {

  redirect("https://www.google.com");

}

 

Request body

By utilising the request.json() method, the function asynchronously parses and retrieves the JSON data from the request

File: /app/api/users/new/route.js

import { NextResponse } from "next/server";

export async function POST(request) {

  const data = await request.json();

  return NextResponse.json({ result: data });

}

screenshot

 

Form Submission

By utilising the request.formData() method, the function asynchronously parses and retrieves the form data from the request.

File: /app/api/form/route.js

import { NextResponse } from "next/server";

export async function POST(request) {

  const formData = await request.formData();

  const name = formData.get("name");

  const email = formData.get("email");

  return NextResponse.json({ name, email });

}

 

File: /app/page.js

export default function Home() {

  return (

    <main>

      <form action="/api/form" method="post">

        <label htmlFor="name">Name:</label>

        <input type="text" id="name" name="name" />

        <label htmlFor="email">Email:</label>

        <input type="email" id="email" name="email" />

        <button type="submit">Submit</button>

      </form>

    </main>

  );

}

screenshot

On submitting the form we get the form data as  response in json format

 

screenshot

 

Conclusion

In summary, choosing between Express and Next.js depends on what you're building. If you want a flexible framework to create APIs or web servers with lots of customization options, go for Express. On the flip side, if you're into React and need features like server-side rendering or making static sites, Next.js is your go-to for a smoother development ride.

One important thing to understand is Express and Next.js can work together! They can complement each other in certain scenarios. For example, you can use Express as a middleware layer for handling API requests in a Next.js application.

Atif Ali

About author
Transitioning from front-end to full-stack web development, I'm eager to share my insights through articles. My constant drive is to explore new technologies and continually push my boundaries.