How to Add Typescript Types to NextJS API Request Body using Zod
Jasser Mark Arioste
In this tutorial, you'll learn how to add typescript types to the NextJS API request body using the typescript schema declaration and validation library, Zod.
Introduction #
When we're using typescript in our apps, we really don't want to use the any
type because this will remove any type-checking in our code and is easily error-prone. However, that's basically what the type NextApiRequest["body"]
is.
Using the zod
library will allow us to create secure and robust NextJS APIs to make sure our request body is free from errors before processing them in the API handlers.
Examining NextApiRequest Type Definition #
To be able to extend NextApiRequest
, I like to first examine the NextApiRequest type from Next's type definition files: utils.d.ts
.
// node_modules/next/dist/shared/lib/utils.d.ts /** * Next `API` route request */ export interface NextApiRequest extends IncomingMessage { /** * Object of `query` values from url */ query: Partial<{ [key: string]: string | string[]; }>; /** * Object of `cookies` from header */ cookies: Partial<{ [key: string]: string; }>; body: any; env: Env; preview?: boolean; /** * Preview data set on the request, if any * */ previewData?: PreviewData; }
12345678910111213141516171819202122232425
As you can see on line 18, the "body"
property is of type any
.
How to Extend the NextApiRequest
Manually
#
And since NextApiRequest
is an interface, we could extend it and override the body property by defining something like the one below on our API route:
// pages/api/hello.ts // Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type { NextApiRequest, NextApiResponse } from "next"; // 👇 Define new request body export interface HelloApiRequest extends NextApiRequest { // let's say our request accepts name and age property body: { name: string; age: number; }; } export default function handler( /*req: NextApiRequest*/ req: HelloApiRequest, res: NextApiResponse ) { const { name, age } = req.body; // 👈 body is now fully typed if (req.method === "POST") { res.status(200).json({ message: `Hello, I'm ${name}, ${age} years old.` }); } else { res.status(405).send("Method not allowed."); } }
123456789101112131415161718192021222324
This is all fine, but relying on typescript alone does not make this code robust. This is great during compile-time, but what about runtime? We know that in software, we should not trust the user input without some type of validation. This is where zod
comes in.
Using zod
to define the schema
#
First, let's install zod
as a dependency:
yarn add zod
Next, let's modify the api/hello.ts
file to use zod
:
// pages/api/hello.ts import type { NextApiRequest, NextApiResponse } from "next"; import { object, string, number, TypeOf } from "zod"; // 👇 Define the schema using zod const helloSchema = object({ name: string(), age: number(), }); // 👇 Define new request body export interface HelloApiRequest extends NextApiRequest { // use TypeOf to infer the properties from helloSchema body: TypeOf<typeof helloSchema>; } export default function handler( /*req: NextApiRequest*/ req: HelloApiRequest, res: NextApiResponse ) { const { name, age } = req.body; // 👈 body is now fully typed same as before. if (req.method === "POST") { // validate the body using safeParse() method const result = helloSchema.safeParse(req.body); if (!result.success) { res.status(400).send({ message: result.error.message, }); } res.status(200).json({ message: `Hello, I'm ${name}, ${age} years old.` }); } else { res.status(405).send("Method not allowed."); } }
12345678910111213141516171819202122232425262728293031
The difference between this and the previous one is that we can easily validate our request body using the schema. This is much better and we get the benefit of automatically generating the body
type using the TypeOf
utility type from zod
.
That's it!
Conclusion #
We learned how to add types to a NextJS API request body by extending the NextApiRequest
interface and using zod schema to automatically generate the body type. Zod is an amazing library and if you'd like to learn more about it, check out the documentation.
If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter.
Credits: Image by Giani Pralea from Pixabay