@fizbix/nest-fastest-validator v2.1.0
Nest-fastest-validator
Fastest-Validator module for Nest.JS based on the fastest-validator package.
Installation
$ npm install @fizbix/nest-fastest-validator fastest-validator class-transformer
Usage
Just import NestFastestValidatorModule
to your app module:
@Module({
imports: [NestFastestValidatorModule.forRoot()]
})
class AppModule {}
Async Options
1. UseFactory
@Module({
imports: [
NestFastestValidatorModule.forRootAsync({
useFactory: () => ({
customRules: {
// rules
}
})
})
]
})
class AppModule {}
2. Use class
@Injectable()
class FastestValidatorConfig implements INestFastestValidatorOptionsFactory {
public createFastestValidatorModuleOptions(): TNestFastestValidatorModuleOptions {
return {
// options
};
}
}
@Module({
imports: [
NestFastestValidatorModule.forRootAsync({
useClass: FastestValidatorConfig
})
]
})
class AppModule {}
Thanks to that, every time if any unknown property is passed to the schema, an error will be thrown.
Create validation Schemas
After module configuration you can define your validation schemas:
NOTE: ValidationSchema
,IsString
,IsNumber
, IsDate
and IsShorthand
are imported from the @fizbix/nest-fastest-validator
package
@ValidationSchema()
export class ProductDto {
@IsString({
min: 3,
max: 25
})
public readonly name: string;
@IsNumber({
integer: false,
positive: true,
convert: true
})
public readonly price: number;
@IsDate({
nullable: false,
convert: true
})
public readonly createdAt: Date;
@IsShorthand('string[] | optional')
public readonly tags: string[];
}
Now - Prepare your controller:
NOTE: The NestFastestValidatorPipe
is imported from @fizbix/nest-fastest-validator
package
@Controller('/products')
@UsePipes(NestFastestValidatorPipe)
class ProductsController {
@Post('/create')
public createNewProduct(@Body() productDTO: ProductDto) {
/// ...
}
}
If we send request with invalid body properties - the following error will be returned to us
{
"statusCode": 400,
"error": "Validation failed",
"messages": [
{
"field": "name",
"message": "The 'name' field is required."
},
{
"field": "price",
"message": "The 'price' field is required."
},
{
"field": "createdAt",
"message": "The 'createdAt' field is required."
}
]
}
You can configure FastestValidatorPipe
by passing options to the constructor:
@UsePipes(
new FastestValidatorPipe({
transformToClass: true,
disableValidationErrorMessages: true,
httpErrorStatusCode: 404
})
)
Globally usage:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new FastestValidatorPipe({
disableValidationErrorMessages: true
})
);
await app.listen(3000);
}
bootstrap();
Dealing with arrays
To validate arrays of objects, you can use the @IsArray
decorator. Package exports function named extractSchemaRules
to extract schema rules from the class. Example:
Single tag schema:
@ValidationSchema()
class Tag {
@IsString()
public name: string;
@IsString()
public description: string;
@IsSemVer()
public version: string;
}
And in the product schema:
@ValidationSchema()
export class Product {
@IsNumber({
positive: true
})
public id: number;
@IsString()
public name: string;
@IsArray({
items: {
type: 'object',
props: extractSchemaRules(Tag)
}
})
public tags: Tag[];
}
Dealing with objects
To validate objects, you can use the @IsObject
decorator, and pass the schema rules to the props
option. Example:
@ValidationSchema()
export class Product {
@IsNumber({
positive: true
})
public id: number;
@IsString()
public name: string;
@IsObject({
props: extractSchemaRules(Tag)
})
public tags: Tag;
}
Validation Service
@fizbix/nest-fastest-validator
package providers ValidationService
class that can be used to validate data:
import { ValidationService } from '@fizbix/nest-fastest-validator';
@Controller('/products')
class ProductsController {
constructor(private readonly validationService: ValidationService) {}
@Post('/create')
public createNewProduct(@Body() productDTO: ProductDto) {
this.validator.validate(ProductDto, {
name: 'test'
});
/// ...
}
}
Validation Service has 3 methods:
validateSync
- returns array of validation errors ornull
if validation passedvalidate
- returnsPromise
that resolves to validation errors ornull
if validation passedvalidateReactive
- returnsObservable
that emits validation errors ornull
if validation passed
You can also use validate
function from @fizbix/nest-fastest-validator
package
import { validate } from '@fizbix/nest-fastest-validator';
export async function validateProductDto(dto: ProductDto) {
const validationErrors = [];
const validationResult = await validate(ProductDto, dto);
if (Array.isArray(validationResult)) {
validationErrors.push(...validationResult);
}
// do something with validation errors
}
Schema strict mode
Thanks to strict mode, you can control what to do when an unknown property is passed to the schema. StrictMode contains 3 options:
remove
- remove unknown properties from the schemathrowError
- throw an error when an unknown property is passed to the schemanone
- do nothing, and pass unknown properties to output
You can enable strict mode in 2 ways:
- Set
strictMode: 'remove'
in each schema
@ValidationSchema({
strictMode: 'remove'
})
- Set
globalSchemaStrictMode
option in module configuration:
@Module({
imports: [
NestFastestValidatorModule.forRoot({
globalSchemaStrictMode: 'throwError'
})
]
})
Decorators
- All decorators accept an object of options that apply to the type being used, for a full list of options please refer to the fastest-validator documentation.
- Package contains a lot of custom decorators based on amazing class-validator package. You can use them in your schemas.
Create own custom decorators
To create a custom decorator, you can use the createCustomDecorator
function from @fizbix/nest-fastest-validator
package. Example:
function isJwt(value: unknown): boolean {
return typeof value === 'string' && isJwtValidator(value);
}
const jwtRule = createCustomRule({
dataType: 'string',
check: ({ value, errors, path }) => {
if (!isJwt(value)) {
errors.push({
type: 'JWT',
field: path,
expected: `Property ${path} should be a valid JWT token`,
actual: value
});
}
return value;
}
});
export const IsJWT = (additionalOptions?: TAdditionalCustomRuleOptions) =>
jwtRule(additionalOptions);
Type TAdditionalCustomRuleOptions
is an type imported from @fizbix/nest-fastest-validator
package and contains the following properties:
type TAdditionalCustomRuleOptions = {
[x: string]: any;
optional?: boolean | undefined;
nullable?: boolean | undefined;
messages?: MessagesType | undefined;
default?: any;
};
Now you can use it on classes:
@ValidationSchema()
export class AuthenticatedUserDto {
@IsJWT()
public readonly token: string;
}
Async Custom Rules
Custom rules can be asynchronous. To do this, just return a Promise
from the check
function:
const myTestRule = createCustomRule({
dataType: 'any',
check: async ({ value, errors, path }) => {
const result = await someAsyncFunction(value);
if (!result) {
errors.push({
type: 'MY_TEST_RULE',
field: path,
expected: `Property ${path} should be a valid`,
actual: value
});
}
return value;
}
});
const MyTestDecorator = (additionalOptions?: TAdditionalCustomRuleOptions) =>
myTestRule(additionalOptions);
And apply the required option in @ValidationSchema
decorator:
@ValidationSchema({
isAsync: true
})
export class AuthenticatedUserDto {
@MyTestDecorator()
public readonly token: string;
}
Thanks to that, the check
function will be called asynchronously
License
Licensed under the MIT license.