Contentlayer 🤝 NextJS API Routes

Assuming you have a NextJS website and you're using Contentlayer to structure and typecheck your content—like I do with this site—it is almost too easy to set up API routes for using your site content in other contexts.

Say we want to make an api endpoint to serve up all the books on this site. Contentlayer helpfully generates a set of all the items in a collection, as well as a TypeScript type for that collection. So our /pages/api/books/index.ts API route handler is incredibly short in the basic implementation:

import { allBooks, Book } from 'contentlayer/generated'
import type { NextApiRequest, NextApiResponse } from 'next' 

export default function handler(
	req: NextApiRequest,
	res: NextApiResponse<Book[]>
) {
	res.status(200).json(allBooks)
}

You can check this out live on my site right now with this endpoint!

If you want a single book endpoint, you would do essentially the same thing with a /pages/api/books/[slug].ts. All we have to do beyond the allBooks case is to search for the book within our collection, and handle the case when it's not found.

import { allBooks, Book } from 'contentlayer/generated'
import type { NextApiRequest, NextApiResponse } from 'next'  

export default function handler(
	req: NextApiRequest,
	res: NextApiResponse<Book | { message: string }>
) {
  const slug = req.query?.slug

	if (!slug) {
		res.status(403)
			.json({ 
				message: '/books/[slug] requires a slug to return a Book.'
			})
	}

	const foundDoc = allBooks.find(
		doc => doc._raw.sourceFileName.includes(slug as string)
	)
	
	if (!foundDoc) {
		res.status(404)
			.json({ 
				message: `No Book found for slug "${slug}"`
			})
	} else {
		res.status(200).json(foundDoc)
	}
}

Here's the endpoint version of one of my favorite recent reads, the-will-to-change.

Adding the ability to filter, search, and so on to the /api/books endpoint would be a fun exercise if you're trying this out!

I don't use these API routes for anything right now, but I think it would be fun to be able to make a CodePen with my book data at some point. Hope you can find some use for this, have fun and stay weird!