Last active
August 20, 2022 21:02
-
-
Save wzulfikar/9894181bb3463128bcba2d5cc91ef94b to your computer and use it in GitHub Desktop.
DEV.to Post: Typing for Next.js API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { captureException } from '@sentry/nextjs'; | |
import { StatusCodes } from 'http-status-codes'; | |
import { NextApiRequest } from 'next'; | |
import { z } from 'zod'; | |
import { NextApiResponseWithData } from '.'; | |
import { validateSchema } from './validateSchema'; | |
type RootOptions = { | |
schema?: z.SomeZodObject; | |
}; | |
type RootHandler = ( | |
handler: ( | |
req: NextApiRequest, | |
res: NextApiResponseWithData | |
) => void | Promise<void>, | |
options?: RootOptions | |
) => ( | |
req: NextApiRequest, | |
res: NextApiResponseWithData | |
) => void | Promise<void>; | |
export const handle: RootHandler = (handler, options) => async (req, res) => { | |
try { | |
if (options?.schema) validateSchema(req, options.schema); | |
await handler(req, res); // Run the actual handler | |
} catch (e) { | |
captureException(e); | |
console.log('error caught in handler:', e); | |
res | |
.status(StatusCodes.INTERNAL_SERVER_ERROR) | |
.json({ success: false, error: (e as Error).message }); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export { z } from "zod"; | |
export * from "./handler"; | |
export * from "./types"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NextApiRequest, NextApiResponse } from "next"; | |
import { z } from "zod"; | |
export type NextApiResponseWithData<TData extends z.ZodTypeAny = z.ZodTypeAny> = | |
NextApiResponse<ApiResult<TData>> & { | |
data: (body: z.TypeOf<TData>) => void; | |
}; | |
type ApiRequest<TSchema extends z.AnyZodObject = z.AnyZodObject> = Omit< | |
NextApiRequest, | |
"query" | "body" | |
> & { | |
body: z.infer<TSchema>["body"]; | |
query: Partial<z.infer<TSchema>["query"]>; | |
}; | |
type ApiResult<TData extends z.ZodTypeAny> = | |
| (TData extends void | |
? { success: true } | |
: { success: true; data: z.infer<TData> }) | |
| { success: false; error: string }; | |
type ApiResponse<TData extends z.ZodTypeAny> = NextApiResponseWithData<TData>; | |
export type ApiHandler< | |
TRequest extends z.AnyZodObject = z.AnyZodObject, | |
TResponse extends z.ZodTypeAny = z.ZodTypeAny | |
> = ( | |
req: ApiRequest<TRequest>, | |
res: ApiResponse<TResponse> | |
) => void | Promise<void>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NextApiRequest } from "next"; | |
import { z } from "zod"; | |
const errorMap: z.ZodErrorMap = (error, ctx) => { | |
let message = ctx.defaultError; | |
const { path, code } = error; | |
switch (code) { | |
case z.ZodIssueCode.invalid_type: | |
if (error.received === "undefined") { | |
message = `${path.join(".")} is required`; | |
} else { | |
const field = path.join("."); | |
const { expected, received } = error; | |
message = `Expected ${expected} got ${received}: ${field}`; | |
} | |
} | |
return { message }; | |
}; | |
export const validateSchema = ( | |
req: NextApiRequest, | |
schema: z.SomeZodObject | |
) => { | |
const schemaPayload = { | |
query: req.query, | |
body: req.body, | |
}; | |
const schemaResult = schema.safeParse(schemaPayload, { errorMap }); | |
if (!schemaResult.success) { | |
throw new Error(schemaResult.error.issues[0].message); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment