In this article, I will show how to use Zod and Open API (Swagger) in a Nest.js, Prisma project.
I made a github repo for this example.
https://github.com/ikeda1729/nestjs-prisma-zod
Using Zod in Nest.js
I use a useful package nestjs-zod
.
https://github.com/risen228/nestjs-zod
With nestjs-zod
, a dto is simply written like this.
import { createZodDto } from 'nestjs-zod'
import { z } from 'nestjs-zod/z'
export const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string(),
})
export class CreateUserDto extends createZodDto(CreateUserSchema) {}
To enable zod validation, add the validation pipe into app.module.ts
.
@Module({
imports: [UsersModule],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_PIPE,
useClass: ZodValidationPipe,
},
],
})
export class AppModule {}
Using Zod with Prisma
I use a useful package zod-prisma-types
.
This package generates zod schemas from a prisma schema file.
Add generator
in the prisma schema and run npx prisma generate
.
generator zod {
provider = "zod-prisma-types"
output = "../src/generated/zod"
createInputTypes = false
}
You will get generated schemas like this.
export const UserSchema = z.object({
id: z.number().int(),
email: z.string(),
name: z.string().nullable(),
})
Integrate Zod into Open API
We can integrate zod schemas using zodToOpenApi
.
This POST users
endpoint simply returns a prisma user entity.
@Post()
@ApiBody({
schema: zodToOpenAPI(CreateUserSchema),
})
@ApiOkResponse({
schema: zodToOpenAPI(UserSchema),
})
async create(@Body() createUserDto: CreateUserDto) {
try {
return await this.usersService.create(createUserDto);
} catch (e: any) {
if (e.code === 'P2002')
throw new HttpException('User already exists', 409);
}
}
The Open API doc looks like this.
The request body and the response body are displayed according to zod schemas.
Let us see if the validation works.
Sending an invalid json to POST users
,
{
"email": "alice email",
"name": "alice"
}
we get the following 400 error.
{
"statusCode": 400,
"message": "Validation failed",
"errors": [
{
"validation": "email",
"code": "invalid_string",
"message": "Invalid email",
"path": [
"email"
]
}
]
}
Here is another example.
The users/:id/posts
endpoint which returns user's posts.
@Get(':id/posts')
@ApiOkResponse({
schema: zodToOpenAPI(z.array(PostSchema)),
})
async getPosts(@Param('id') id: number) {
return await this.usersService.getPosts(id);
}
We see the response body is the array of the post entity.
Conclusion
With nestjs-zod
and zod-prisma-types
, we can easily integrate Zod into Nest.js Prisma projects.
Top comments (3)
Why don't you wanna use class-validator?
class-validator is OK too, of course.
I feel like it's redundant to do write @ApiProperty on each field.
Additionally, it is convenient to generate zod shcemas from a prisma schema.