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));
}
};