Using Next.js API routes

Next.JS comes with a useful feature out of the box, api routes. Files created in the `pages/api/` folder are treated as an endpoint rather than a page. Instead of exporting a React component to display your UI, you can export a function returning, say, a JSON response.

Map of computers

Table of contents

Usage

Next.JS comes with a useful feature out of the box, api routes. Files created in the pages/api/ folder are treated as an endpoint rather than a page. Instead of exporting a React component to display your UI, you can export a function returning, say, a JSON response.

For example, if you wanted to return a post from your CMS, you could write the following in file pages/api/post.js :

/**
 * NextJS API function
 * https://nextjs.org/docs/api-routes/introduction)
 */
export default (request, response) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'application/json')
  res.end(JSON.stringify({ title: 'My Post' }))
}

If we wanted to handle multiple methods in a single route, we could check the method property from the request object.

export default (req, res) => {
  switch (req.method) {
    case 'GET':
      // process GET requests
      break

    case 'POST':
      // process POST requests
      break

    default:
      res.status(405).end() //Method Not Allowed

      // process every other method
      break
  }
}

API Routes also support Next.JS dynamic routes and can be used used to pass a query to our routes.

For example, if we wanted to fetch our posts based on their uid, we could write the following in the file pages/api/post/uid].js

export default async (req, res) => {
  // use the uid from the reauest's query to fetch our post from our CMS
  const post = await fetchPostFromCMS(req.query.uid)

  res.statusCode = 200
  res.end(JSON.stringify(post))
}

Bonus

One great use for API functions is creating a sitemap for your Next.JS project. The function below is the very same code for our old website.

import { NextApiRequest, NextApiResponse } from 'next'
import { SitemapStream, streamToPromise } from 'sitemap'
import posts from '../posts/post-index'

export default async (req: NextApiRequest, res: NextApiResponse) => {
  try {
    const smStream = new SitemapStream({
      hostname: `https://${req.headers.host}`
    })

    // Create URL row for each static page
    staticPages.forEach((page) => {
      smStream.write({
        changefreq: 'monthly',
        priority: 0.5,
        ...page
      })
    })

    // Create URL row for each post
    Object.entries(posts).forEach(([name, metadata]) => {
      smStream.write({
        title: name,
        url: `/posts/${metadata.slug}`,
        changefreq: 'weekly',
        priority: 0.9
      })
    })

    // End sitemap stream
    smStream.end()

    // XML sitemap string
    const sitemapOutput = (await streamToPromise(smStream)).toString()

    // Change headers
    res.writeHead(200, {
      'Content-Type': 'application/xml'
    })

    res.end(sitemapOutput)
  } catch (e) {
    res.send(JSON.stringify(e))
  }
}