BenLorantfy/nestjs-zod
All NestJS + Zod utilities you need
✨ A seamless validation solution for your NestJS application ✨
by @benlorantfy
✨ Create nestjs DTOs from zod schemas
✨ Validate / parse request body, query params, and url params using zod
✨ Serialize response bodies using zod
✨ Automatically generate OpenAPI documentation using zod
✨ Supports zod codecs
nestjs-zod can be automatically setup by running the following command:
npx nestjs-zod-cli /path/to/nestjs/project
This command runs a codemod that adds the validation pipe, serialization interceptor, http exception filter, and swagger cleanup function
Alternatively, you can follow the manual setup steps below
Install the package:
No download data available
No tracked packages depend on this.
npm install nestjs-zod # Note: zod ^3.25.0 || ^4.0.0 is also required
Add ZodValidationPipe to the AppModule
ZodValidationPipe is required in order to validate the request body, query, and params
+ import { APP_PIPE } from '@nestjs/core';
+ import { ZodValidationPipe } from 'nestjs-zod';
@Module({
imports: [],
controllers: [AppController],
providers: [
+ {
+ provide: APP_PIPE,
+ useClass: ZodValidationPipe,
+ },
]
})
export class AppModule {}
Add ZodSerializerInterceptor to the AppModule
ZodSerializerInterceptor is required in order to validate the response bodies
- import { APP_PIPE } from '@nestjs/core';
+ import { APP_PIPE, APP_INTERCEPTOR } from '@nestjs/core';
- import { ZodValidationPipe } from 'nestjs-zod';
+ import { ZodValidationPipe, ZodSerializerInterceptor } from 'nestjs-zod';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: APP_PIPE,
useClass: ZodValidationPipe,
},
+ {
+ provide: APP_INTERCEPTOR,
+ useClass: ZodSerializerInterceptor,
+ },
]
})
export class AppModule {}
[OPTIONAL] Add an HttpExceptionFilter
An HttpExceptionFilter is required in order to add custom handling for zod errors
- import { APP_PIPE, APP_INTERCEPTOR } from '@nestjs/core';
+ import { APP_PIPE, APP_INTERCEPTOR, APP_FILTER } from '@nestjs/core';
import { ZodValidationPipe, ZodSerializerInterceptor } from 'nestjs-zod';
+ import { HttpExceptionFilter } from './http-exception.filter';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: APP_PIPE,
useClass: ZodValidationPipe,
},
{
provide: APP_INTERCEPTOR,
useClass: ZodSerializerInterceptor,
},
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
}
]
})
export class AppModule {}
+ // http-exception.filter
+ @Catch(HttpException)
+ export class HttpExceptionFilter extends BaseExceptionFilter {
+ private readonly logger = new Logger(HttpExceptionFilter.name);
+
+ catch(exception: HttpException, host: ArgumentsHost) {
+ if (exception instanceof ZodSerializationException) {
+ const zodError = exception.getZodError();
+ if (zodError instanceof ZodError) {
+ this.logger.error(`ZodSerializationException: ${zodError.message}`);
+ }
+ }
+
+ super.catch(exception, host);
+ }
+ }
[OPTIONAL] Add cleanupOpenApiDoc
Important: This step is important if using
@nestjs/swagger
cleanupOpenApiDoc is required if using @nestjs/swagger to properly post-process the OpenAPI doc
- SwaggerModule.setup('api', app, openApiDoc);
+ SwaggerModule.setup('api', app, cleanupOpenApiDoc(openApiDoc));
Check out the example app for a full example of how to integrate nestjs-zod in your nestjs application
createZodDto (Create a DTO from a Zod schema)function createZodDto<TSchema extends UnknownSchema, TCodec extends boolean = false>(schema: TSchema, options?: { codec: TCodec }): ZodDto<TSchema, TCodec>;
Creates a nestjs DTO from a zod schema. These zod DTOs can be used in place of class-validator / class-transformer DTOs. Zod DTOs are responsible for three things:
ZodValidationPipe to validate incoming client data againstnestjs/swagger[!NOTE] For this feature to work, please ensure
ZodValidationPipeis setup correctly
schema - A zod schema. You can "bring your own zod", including zod v3 schemas, v4 schemas, zod mini schemas, etc. The only requirement is that the schema has a method called parseoptions
options.codec - If set to true, then when serializing responses nestjs-zod will use encode instead of parse. See more information about codecs in the zod documentationimport { createZodDto } from 'nestjs-zod'
import { z } from 'zod'
const CredentialsSchema = z.object({
username: z.string(),
password: z.string(),
})
// class is required for using DTO as a type
class CredentialsDto extends createZodDto(CredentialsSchema) {}
@Controller('auth')
class AuthController {
async signIn(@Body() credentials: CredentialsDto) {}
}
ZodValidationPipe (Get nestjs to validate using zod)ZodValidationPipe is needed to ensure zod DTOs actually validate incoming request data when using @Body(), @Params(), or @Query() parameter decorators
When the data is invalid it throws a ZodValidationException.
import { ZodValidationPipe } from 'nestjs-zod'
import { APP_PIPE } from '@nestjs/core'
@Module({
providers: [
{
provide: APP_PIPE,
useClass: ZodValidationPipe,
},
],
})
export class AppModule {}
import { ZodValidationPipe } from 'nestjs-zod'
// controller-level
@UsePipes(ZodValidationPipe)
class AuthController {}
class AuthController {
// route-level
@UsePipes(ZodValidationPipe)
async signIn() {}
}
createZodValidationPipe (Creating custom validation pipe)export function createZodValidationPipe({ createValidationException, strictSchemaDeclaration }: ZodValidationPipeOptions = {}): ZodValidationPipeClass
Creates a custom zod validation pipe
import { createZodValidationPipe } from 'nestjs-zod'
const MyZodValidationPipe = createZodValidationPipe({
// provide custom validation exception factory
createValidationException: (error: ZodError) =>
new BadRequestException('Ooops'),
})
params.createValidationException - A callback that will be called with the zod error when a parsing error occurs. Should return a new instance of Errorparams.strictSchemaDeclaration - If true, throws a ZodSchemaDeclarationException when the pipe encounters a parameter that is not typed with a nestjs-zod DTO. It's recommended to set this to true to ensure all request data is properly validatedZodValidationExceptionIf the zod request parsing fails, then nestjs-zod will throw a ZodValidationException, which will result in the following HTTP response:
{
"statusCode": 400,
"message": "Validation failed",
"errors": [
{
"code": "too_small",
"minimum": 8,
"type": "string",
"inclusive": true,
"message": "String must contain at least 8 character(s)",
"path": ["password"]
}
]
}
You can customize the exception and HTTP response by either 1) creating a custom validation pipe using createZodValidationPipe or 2) handling ZodValidationException inside an exception filter
Here is an example exception filter:
@Catch(ZodValidationException)
export class ZodValidationExceptionFilter implements ExceptionFilter {
catch(exception: ZodValidationException) {
exception.getZodError() // -> ZodError
}
}
ZodSchemaDeclarationExceptionIf strictSchemaDeclaration is set to true in createZodValidationPipe and a request parameter is not typed with a nestjs-zod DTO (e.g. using a primitive type like string or a class-validator DTO), then nestjs-zod will throw a ZodSchemaDeclarationException, which will result in the following HTTP response:
{
"statusCode": 500,
"message": "Internal Server Error"
}
This is useful for catching cases during development where request data might not be properly validated. You can handle this exception in an exception filter if you want to customize the response:
@Catch(ZodSchemaDeclarationException)
export class ZodSchemaDeclarationExceptionFilter implements ExceptionFilter {
catch(exception: ZodSchemaDeclarationException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(500).json({
statusCode: 500,
message: 'Missing nestjs-zod schema declaration',
});
}
}
ZodSerializerDto (Set zod DTO to serialize responses with)function ZodSerializerDto(dto: ZodDto | UnknownSchema | [ZodDto] | [UnknownSchema])
Parses / serializes the return value of a controller method using the provided zod schema. This is especially useful to prevent accidental data leaks.
[!NOTE] Instead of
ZodSerializerDto, consider usingZodResponse, which has some improvements overZodSerializerDto
[!NOTE] For this feature to work, please ensure
ZodSerializerInterceptoris setup correctly
options.dto - A ZodDto (or zod schema) to serialize the response with. If passed with array syntax ([MyDto]) then it will parse as an array. Note that the array syntax does not work with zod/mini, because it requires the schema have an .array() methodconst UserSchema = z.object({ username: string() })
class UserDto extends createZodDto(UserSchema) {}
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@ZodSerializerDto(UserDto)
getUser(id: number) {
return this.userService.findOne(id)
}
}
In the above example, if the userService.findOne method returns password, the password property will be stripped out thanks to the @ZodSerializerDto decorator.
Also note that arrays can be serialized using [] syntax like this:
class BookDto extends createZodDto(z.object({ title: string() })) {}
@Controller('books')
export class BooksController {
constructor() {}
@ZodSerializerDto([BookDto])
getBooks() {
return [{ title: 'The Martian' }, { title: 'Hail Marry' }];
}
}
Or by using an array DTO:
class BookListDto extends createZodDto(z.array(z.object({ title: string() }))) {}
@Controller('books')
export class BooksController {
constructor() {}
@ZodSerializerDto(BookListDto)
getBooks() {
return [{ title: 'The Martian' }, { title: 'Hail Marry' }];
}
}
ZodSerializerInterceptor (Get nestjs to serialize responses with zod)To ensure ZodSerializerDto works correctly, ZodSerializerInterceptor needs to be added to the AppModule
[!NOTE] Also see
ZodSerializationExceptionfor information about customizing the serialization error handling
This should be done in the AppModule like so:
@Module({
...
providers: [
...,
{ provide: APP_INTERCEPTOR, useClass: ZodSerializerInterceptor },
],
})
export class AppModule {}
createZodSerializerInterceptor (Creating custom serializer interceptor)export function createZodSerializerInterceptor({ reportInput }: ZodSerializerInterceptorOptions = {}): ZodSerializerInterceptorClass
Creates a custom zod serializer interceptor
params.reportInput - When set to true, includes the input value in Zod error issues. This is useful for debugging serialization errors. Only supported in Zod v4.import { createZodSerializerInterceptor } from 'nestjs-zod'
import { APP_INTERCEPTOR } from '@nestjs/core'
const CustomZodSerializerInterceptor = createZodSerializerInterceptor({
reportInput: true,
})
@Module({
providers: [
{
provide: APP_INTERCEPTOR,
useClass: CustomZodSerializerInterceptor,
},
],
})
export class AppModule {}
ZodResponse (Sync run-time, compile-time, and docs-time schemas)function ZodResponse<TSchema extends UnknownSchema>({ status, description, type }: { status?: number, description?: string, type: ZodDto<TSchema> & { io: "input" } }): (target: object, propertyKey?: string | symbol, descriptor?: Pick<TypedPropertyDescriptor<(...args: any[]) => input<TSchema>|Promise<input<TSchema>>>, 'value'>) => void
function ZodResponse<TSchema extends RequiredBy<UnknownSchema, 'array'>>({ status, description, type }: { status?: number, description?: string, type: [ZodDto<TSchema> & { io: "input" }] }): (target: object, propertyKey?: string | symbol, descriptor?: Pick<TypedPropertyDescriptor<(...args: any[]) => Array<input<TSchema>>|Promise<Array<input<TSchema>>>>, 'value'>) => void
Consolidation of multiple decorators that allows setting the run-time, compile-time, and docs-time schema all at once
[!NOTE] For this feature to work, please ensure
ZodSerializerInterceptorandcleanupOpenApiDocare setup correctly
params.status - Optionally sets the "happy-path" status of the response. If provided, sets the status code using @HttpCode from nestjs/common and using @ApiResponse from nestjs/swaggerparams.description - Optionally sets a description of the response using @ApiResponseparams.type - Sets the run-time (via @ZodSerializerDto), compile-time (via TypeScript), and docs-time (via @ApiResponse) response type.You may find yourself duplicating type information:
@ZodSerializer(BookDto)
@ApiOkResponse({
status: 200,
type: BookDto
})
getBook(): BookDto {
...
}
Here, BookDto is repeated 3 times:
If these 3 spots get out of sync, this may cause bugs. If you want to remove this duplication, you can consolidate using ZodResponse:
- @ZodSerializer(BookDto)
- @ApiOkResponse({
- status: 200,
- type: BookDto.Output
- })
- getBook(): BookDto {
+ @ZodResponse({ type: BookDto })
+ getBook()
...
}
@ZodResponse will set all these things. It will set the DTO to use to serialize, it will set the DTO to use for the OpenAPI documentation, and it will throw a compile-time typescript error if the method does not return data that matches the zod input schema
This is pretty powerful, because it ensures the run-time, compile-time, and docs-time representations of your response are all in sync. For this reason, it's recommended to use @ZodResponse instead of repeating the DTO three times.
ZodSerializationExceptionIf the zod response serialization fails, then nestjs-zod will throw a ZodSerializationException, which will result in the following HTTP response:
{
"message": "Internal Server Error",
"statusCode": 500,
}
You can customize the exception and HTTP response handling ZodSerializationException inside an exception filter
See the example app here for more information.
[!NOTE] For additional documentation, follow Nest.js' Swagger Module Guide, or you can see the example application here
If you have @nestjs/swagger setup, documentation will automatically be generated for:
@Body() body: MyDto@ApiOkResponse({ type: MyDto.Output }) (or @ZodResponse({ type: MyDto }))@Query() query: MyQueryParamsDtoTo generate the OpenAPI document, nestjs-zod uses z.toJSONSchema for zod v4 schemas. It's recommended to review the zod documentation itself for more information about how the OpenAPI document is generated
For zod v3 schemas, nestjs-zod uses a custom-built (deprecated) function called zodV3ToOpenAPI that generates the OpenAPI document by inspecting the zod schema directly.
However, please note cleanupOpenApiDoc is required to get the correct OpenAPI output, as shown below:
cleanupOpenApiDoc (Ensure proper OpenAPI output)function cleanupOpenApiDoc(doc: OpenAPIObject, options?: { version?: '3.1' | '3.0' | 'auto' }): OpenAPIObject
Cleans up the generated OpenAPI doc by applying some post-processing and ensuring it complies with the optionally specified OpenAPI version
[!IMPORTANT] Using this function is required when using
@nestjs/swaggerto get the correct OpenAPI output!!
doc - The OpenAPI doc generated by SwaggerModule.createDocumentoptions.version - The OpenAPI version to use while cleaning up the document.
auto (default) - Uses the version specified in the OpenAPI document (The version in the OpenAPI can be changed by using the setOpenAPIVersion method on the swagger document builder).3.1 - Generates schemas that take advantage of OpenAPI 3.1 syntax. See table below for more information3.0 - Generates schemas that are compatible with OpenAPI 3.0. See table below for more information| 3.0 | 3.1 | |
|---|---|---|
| null | { type: 'string', nullable: true } | { anyOf: [{ type: 'string'}, { type: 'null' }] } |
| literal | { type: 'string', enum: ['hello'] } | { type: 'string', const: 'hello' } |
| id | Omitted | { id: 'Author', type: 'object', ... } |
To complete the swagger integration/setup, cleanupOpenApiDoc needs to be called with the generated open api doc, like so:
const openApiDoc = SwaggerModule.createDocument(app,
new DocumentBuilder()
.setTitle('Example API')
.setDescription('Example API description')
.setVersion('1.0')
.build(),
);
- SwaggerModule.setup('api', app, openApiDoc);
+ SwaggerModule.setup('api', app, cleanupOpenApiDoc(openApiDoc));
Note that z.toJSONSchema can generate two versions of any zod schema: "input" or "output". This is what the zod documentation says about this:
Some schema types have different input and output types, e.g. ZodPipe, ZodDefault, and coerced primitives.
Note that by default, when generating OpenAPI documentation, nestjs-zod uses the "input" version of a schema, except for @ZodResponse which always generates the "output" version of a schema. If you want to explicitly use the "output" version of a schema when generating OpenAPI documentation, you can use the .Output property of a zod DTO. For example, this makes sense when using @ApiResponse:
@ApiResponse({
type: MyDto.Output
})
However, it's recommended to use @ZodResponse over @ApiResponse, which automatically handles this for you:
@ZodResponse({
type: MyDto // <-- No need to do `.Output` here
})
Zod 4.1 introduced a new feature called "codecs". There is more information about codecs in the zod documentation
nestjs-zod supports codecs. If the codec: true option is used when creating the zod DTO, then parse will be used for request bodies, and encode will be used when serializing response bodies.
codecs can enable, in some cases, using one zod schema, instead of two, for both the request and response
const stringToDate = z.codec(
z.iso.datetime(),
z.date(),
{
decode: (isoString) => new Date(isoString),
encode: (date) => date.toISOString(),
}
);
class BookDto extends createZodDto(z.object({
title: z.string(),
dateWritten: stringToDate
}), {
codec: true
}) { }
@Controller('books')
class BookController {
constructor() { }
@Post()
@ZodResponse({
type: BookDto
})
createBook(@Body() book: BookDto) {
return book;
}
}
See the example app here for a full example.
You can also externalize and reuse schemas across multiple DTOs. If you add .meta({ id: "MySchema" }) to any zod schema, then that schema will be added directly to components.schemas in the OpenAPI documentation. For example, this code:
const Author = z.object({ name: z.string() }).meta({ id: "Author" })
class BookDto extends createZodDto(z.object({ title: z.string(), author: Author })) { }
class BlogPostDto extends createZodDto(z.object({ title: z.string(), author: Author })) { }
Will result in this OpenAPI document:
{
"components": {
"schemas": {
"Author": {
// ...
},
"BookDto": {
"type": "object",
"properties": {
"author": {
"$ref": "#/components/schemas/Author"
},
"required": ["author"]
}
},
"BlogPostDto": {
"type": "object",
"properties": {
"author": {
"$ref": "#/components/schemas/Author"
},
"required": ["author"]
}
}
}
},
// ...
}
Note that schemas are named / displayed in SwaggerUI according to the following logic:
id property in .meta({ id: 'MySchema' })@ZodResponse()), nestjs-zod suffixes the id set by .meta({ id: 'MySchema' }) with _Output, so SwaggerUI displays, for example, MySchema_Output. This is important to avoid collision with input schemas.title is set by .meta({ title: ... }), then SwaggerUI will display title. Note that unlike ids, there is no duplicate checking for titles, so it's the consumer's responsibility to avoid confusion when using title.zodV3ToOpenAPI (DEPRECATED)[!CAUTION]
zodV3ToOpenAPIis deprecated and will not be supported soon, since zod v4 adds built-in support for generating OpenAPI schemas from zod schemas. See MIGRATION.md for more information.
You can convert any Zod schema to an OpenAPI JSON object:
import { zodToOpenAPI } from 'nestjs-zod'
import { z } from 'zod'
const SignUpSchema = z.object({
username: z.string().min(8).max(20),
password: z.string().min(8).max(20),
sex: z
.enum(['male', 'female', 'nonbinary'])
.describe('We respect your gender choice'),
social: z.record(z.string().url())
})
const openapi = zodV3ToOpenAPI(SignUpSchema)
The output will be the following:
{
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 8,
"maxLength": 20
},
"password": {
"type": "string",
"minLength": 8,
"maxLength": 20
},
"sex": {
"description": "We respect your gender choice",
"type": "string",
"enum": ["male", "female", "nonbinary"]
},
"social": {
"type": "object",
"additionalProperties": {
"type": "string",
"format": "uri"
}
},
"birthDate": {
"type": "string",
"format": "date-time"
}
},
"required": ["username", "password", "sex", "social", "birthDate"]
}
validate (DEPRECATED)[!CAUTION]
validateis deprecated and will not be supported soon. It is recommended to use.parsedirectly. See MIGRATION.md for more information.
If you don't like ZodGuard and ZodValidationPipe, you can use validate function:
import { validate } from 'nestjs-zod'
validate(wrongThing, UserDto, (zodError) => new MyException(zodError)) // throws MyException
const validatedUser = validate(
user,
UserDto,
(zodError) => new MyException(zodError)
) // returns typed value when succeed
ZodGuard (DEPRECATED)[!CAUTION] Guard-related functions are deprecated and will not be supported soon. It is recommended to use guards for authorization, not validation. See MIGRATION.md for more information.
[!CAUTION]
ZodGuardis deprecated and will not be supported soon. It is recommended to use guards for authorization, not validation. See MIGRATION.md for more information.
Sometimes, we need to validate user input before specific Guards. We can't use Validation Pipe since NestJS Pipes are always executed after Guards.
The solution is ZodGuard. It works just like ZodValidationPipe, except for that is doesn't transform the input.
It has 2 syntax forms:
@UseGuards(new ZodGuard('body', CredentialsSchema))@UseZodGuard('body', CredentialsSchema)Parameters:
'body' | 'query' | 'params'ZodValidationPipe)When the data is invalid - it throws ZodValidationException.
import { ZodGuard } from 'nestjs-zod'
// controller-level
@UseZodGuard('body', CredentialsSchema)
@UseZodGuard('params', CredentialsDto)
class MyController {}
class MyController {
// route-level
@UseZodGuard('query', CredentialsSchema)
@UseZodGuard('body', CredentialsDto)
async signIn() {}
}
createZodGuard (Creating custom guard)[!CAUTION]
createZodGuardis deprecated and will not be supported soon. It is recommended to use guards for authorization, not validation. See MIGRATION.md for more information.
import { createZodGuard } from 'nestjs-zod'
const MyZodGuard = createZodGuard({
// provide custom validation exception factory
createValidationException: (error: ZodError) =>
new BadRequestException('Ooops'),
})
@nest-zod/z (DEPRECATED)[!CAUTION]
@nest-zod/zis no longer supported and has no impact on the OpenAPI generation. It is recommended to usezoddirectly. See MIGRATION.md for more information.
@nest-zod/z provides a special version of Zod. It helps you to validate the user input more accurately by using our custom schemas and methods.
ZodDateString[!CAUTION]
@nest-zod/zis no longer supported and has no impact on the OpenAPI generation. It is recommended to usezoddirectly. See MIGRATION.md for more information.
In HTTP, we always accept Dates as strings. But default Zod only has validations for full date-time strings. ZodDateString was created to address this issue.
// 1. Expect user input to be a "string" type
// 2. Expect user input to be a valid date (by using new Date)
z.dateString()
// Cast to Date instance
// (use it on end of the chain, but before "describe")
z.dateString().cast()
// Expect string in "full-date" format from RFC3339
z.dateString().format('date')
// [default format]
// Expect string in "date-time" format from RFC3339
z.dateString().format('date-time')
// Expect date to be the past
z.dateString().past()
// Expect date to be the future
z.dateString().future()
// Expect year to be greater or equal to 2000
z.dateString().minYear(2000)
// Expect year to be less or equal to 2025
z.dateString().maxYear(2025)
// Expect day to be a week day
z.dateString().weekDay()
// Expect year to be a weekend
z.dateString().weekend()
Valid date format examples:
2022-05-15Valid date-time format examples:
2022-05-02:08:33Z2022-05-02:08:33.000Z2022-05-02:08:33+00:002022-05-02:08:33-00:002022-05-02:08:33.000+00:00Errors:
invalid_date_string - invalid date
invalid_date_string_format - wrong format
Payload:
expected - 'date' | 'date-time'invalid_date_string_direction - not past/future
Payload:
expected - 'past' | 'future'invalid_date_string_day - not weekDay/weekend
Payload:
expected - 'weekDay' | 'weekend'too_small with type === 'date_string_year'
too_big with type === 'date_string_year'
ZodPassword[!CAUTION]
@nest-zod/zis no longer supported and has no impact on the OpenAPI generation. It is recommended to usezoddirectly. See MIGRATION.md for more information.
ZodPassword is a string-like type, just like the ZodDateString. As you might have guessed, it's intended to help you with password schemas definition.
Also, ZodPassword has a more accurate OpenAPI conversion, comparing to regular .string(): it has password format and generated RegExp string for pattern.
// Expect user input to be a "string" type
z.password()
// Expect password length to be greater or equal to 8
z.password().min(8)
// Expect password length to be less or equal to 100
z.password().max(100)
// Expect password to have at least one digit
z.password().atLeastOne('digit')
// Expect password to have at least one lowercase letter
z.password().atLeastOne('lowercase')
// Expect password to have at least one uppercase letter
z.password().atLeastOne('uppercase')
// Expect password to have at least one special symbol
z.password().atLeastOne('special')
Errors:
invalid_password_no_digitinvalid_password_no_lowercaseinvalid_password_no_uppercaseinvalid_password_no_specialtoo_small with type === 'password'too_big with type === 'password'This library was originally created by risen228 and now maintained by BenLorantfy (that's me!)
I'm for hire! Check out my resume here. You can email me at ben@lorantfy.com if you want to chat.