Telerik blogs

In this post, we’ll see how to set up API routes using Next.js, the request object and response helpers.

It is important to remember that some websites provide visitors with more than simply serving webpages. In some situations, we may need a backend to handle features such as allowing users to sign up for newsletters, receiving user feedback, retrieving data from a database, etc.

Next.js introduced the API routes feature in version 9 to allow us to build API endpoints as part of our Next.js application without having to write any extra custom server code.

This article will go over the crucial components of the Next.js API routes. We’ll see how to use Next.js to set up API routes, the request object, response helpers and other concepts.

Overview of How Next.js API Routes Work

Next.js leverages the application’s folder structure to create API routes. In the pages folder at the root level of the application, there is an api folder already added by create-next-app. You can create JavaScript files within that folder to represent all of your application’s API routes.

Next.js maps any file in the pages/api folder to /api/<file-name> and treats them as an API route instead of a page. For example, creating a pages/api/products.js file will create a /api/products API route. We can also create the /api/products route by adding a pages/api/products/index.js file. It also allows the index file mechanism similar to that of client-side routing in Next.js.

With this, you can write backend code and add business logic to your application without having to do some other API routes configuration or write any additional custom server code. For an API route to work, each file must export a function as default that accepts two parameters—the request and response objects.

Project Setup

Create a Next.js app using the following command:

npx create-next-app api-demo

Creating an API Route

Create a new file called first-route.js in the pages/api folder and add the following to it:

export default function handler(req, res) {
  res.status(200).json({ message: "My first API route" });
}

Yeah, that’s it! Creating an API route with Next.js is that simple.

We added a function to the newly created file. The function serves as a controller that handles requests coming to that (pages/api/first-route) route. It takes two parameters and returns a response with a status and JSON object using some predefined response helpers. More details about the request object and response helpers will be given in subsequent sections of this article.

Other backend logic can be added to the route files, but it must always comply with the requirement of exporting a function as default.

To test if the API route works, open your browser and navigate to pages/api/first-route to view the API response.

First API route response

The Request Object

As previously stated, the Next.js API route handler method receives two arguments, one of which is the request (req) object. The req object is an instance of http.IncomingMessage, and it represents the request information received from the client sending the request. It also includes the request headers, the request method, the requested URL, etc.

Next.js also provides built-in middlewares for parsing and extending the incoming request (req) object. These are the middlewares:

  • req.body: By default, Next.js parses the request body, so you don’t have to install another third-party body-parser module. req.body comprises an object parsed by content-type as specified by the client. It defaults to null if no body was specified.

  • req.query: Next.js also parses the query string attached to the request URL. req.query is an object containing the query parameters and their values, or an empty object {} if no query string was attached.

  • req.cookies: It contains the cookies sent by the request. It also defaults to an empty object {} if no cookies are specified.

The Response Helpers

The other half of the two required parameters defined in the API route handlers is the response (res) object. It is an instance of http.ServerResponse, with additional helper methods that help enhance the developer experience and speed up the creation of new API endpoints.

A few of the helper methods are:

  • res.json(body): It is used to send a JSON response back to the client. It takes as an argument an object which must be serializable.
export default function handler(req, res) {
  res.json({
    message: "Successful",
    data: { name: "A new JSON API reponse data" },
  });
}
  • res.send(body): Used to send the HTTP response. The body can either be a string, an object or a buffer.
export default function handler(req, res) {
  res.send("Hello world!!...");
}
  • res.status(code): It is a function used to set the response status code. It accepts a valid HTTP status code as an argument.
export default function handler(req, res) {
  try {
    //some code...
    res.status(200).json({
      message: "Successful",
      data: { data },
    });
  } catch (error) {
    res.status(500).json({
      error,
    });
  }
}

In the code above, we defined a route handler function that returns a different status code and response object depending on whether or not an error occurs.

You can learn more here about other response helper methods provided by Next.js.

Handling Multiple HTTP Verbs

When working with API routes/endpoints, it is common to use nouns that represent the entity of the endpoint that we’re retrieving or manipulating as the pathname instead of using verbs in our endpoint paths.

For example, instead of having separate routes to get users—/pages/api/getUsers, update users—pages/api/updateUsers, add users—pages/api/addUsers, we want to have a single route pages/api/users but with different request method to specify the action we want. In our case, GET, PATCH and POST.

Next.js API routes allow us to specify multiple HTTP verbs for the same API route all in one file. To work with that, you need to use a conditional statement to differentiate between the various request methods you want to work with in your API route.

An example using the switch statement is shown below:

    export default function handler(req, res) {
        switch (req.method) {
          case 'GET':
            //some code...
            res.status(200).json({//response object})
            break;

          case 'POST':
            //some code...
            res.status(201).json({//response object})
            break;

          case 'PATCH':
            //some code...
            res.status(200).json({//response object})
            break;

          default:
            res.status(405).end(`${method} Not Allowed`);
            break;
        }
      }

In the code above, we defined a switch statement that allows us to run code snippets and return different responses for each case of the request method. We also specified a default condition that yields an error if none of the cases are met.

There is also a library called next-connect known as a minimal router and middleware layer for Next.js. It uses an approach similar to Express.js for API routing. It also simplifies the handling of various HTTP verbs. You can learn more here.

Dynamic API Routes

Next.js allows us to create dynamic API routes similar to the convention used for client-side routing in Next.js. To create a dynamic API route, enclose the name of the route file in square brackets, e.g. [id].js.

Let’s create a dynamic API route. Create a file called [userId].js in the page/api folder and add the following to it:

export default function handler(req, res) {
  const { userId } = req.query;
  //some other codes...
  res.status(200).json({ userId });
}

Dynamic API routes

Just like client-side routing, Next.js also allows us to define a catch-all API route, i.e., we can have multiple dynamic path segments in an API route. To achieve this, add three dots inside the square brackets before the file name. e.g. […slug].js.

Creating a catch-all route file like pages/api/products/[…slug].js will match /api/products/ball, /api/products/ball/red, /api/products/ball/red/big and so on.

Matched parameter values will not be sent as a query object but collected into an array instead. Therefore for the three routes we used as an example, we will have the objects {"slug": ["ball"]}, {"slug": ["ball", "red"]} and {"slug": ["ball", "red", "big"]}, respectively.

Also, predefined API routes take precedence over dynamic API routes, and dynamic API routes take precedence over catch-all API routes.

Setting Custom Configurations

Next.js provides a config object that, when exported, can be used to change some of the default configurations of the application. It has a nested api object that deals with configurations available for API routes.

For example, we can disable the default body parser provided by Next.js.

export default function handler(req, res) {
  //....
}
export const config = {
  api: {
    bodyParser: false,
  },
};

We can set many other custom API configurations using the config object. Click this link to learn more.

Using Third-Party Middlewares

The Next.js team provides a runMiddleware helper function that allows you to run any Connect (a middleware layer for Node.js) compatible middleware.

function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result);
      }
      return resolve(result);
    });
  });
}

The helper function takes the request object, the response object and an instance of the third-party middleware as parameters. It waits for middleware to execute before continuing and throws an error if it fails.

You may now use the helper function to run any Connect compatible middleware in your application. For example, to configure CORS (Cross-Origin Resource Sharing) for your API route, open your terminal and at the root of your application, run the following command to install the cors package as a dependency:

npm install cors

Next, open your API route file and add the following to it:

    import Cors from 'cors'
    const cors = Cors({
      methods: ['GET', 'HEAD', 'POST'],
    })
    function runMiddleware(req, res, fn) {
      return new Promise((resolve, reject) => {
        fn(req, res, (result) => {
          if (result instanceof Error) {
            return reject(result);
          }
          return resolve(result);
        });
      });
    }
    export default async function handler(req, res) {
      await runMiddleware(req, res, cors)
      //other api logic
      res.status(//status-code).json({//reponse object});
    }

In the code above, we imported Cors and created an instance of it. We then ran the middleware using the runMiddleware helper function inside the handler function.

Conclusion

In this article, we’ve looked at setting up an API route in Next.js. Next.js simplifies the process of implementing an API for your applications. It offers a couple of advantages: it does not require configuration, isolates every handler as a standalone function, has great middleware support, etc.


Ifeoma-Imoh
About the Author

Ifeoma Imoh

Ifeoma Imoh is a software developer and technical writer who is in love with all things JavaScript. Find her on Twitter or YouTube.

Related Posts

Comments

Comments are disabled in preview mode.