Documentation
Validate Fireclass models with class-validator and transform nested values before writes.
Fireclass integrates class-validator and class-transformer into save().
Validation is model-driven: place constraints next to fields, then handle a
single Fireclass error type when a write is rejected.
Every call to save() follows this order:
plainToInstance.class-validator with forbidUnknownValues: false.ValidationFailedError when constraints fail.id.An invalid model never reaches the adapter write.
import { Collection } from "@dharayush7/fireclass-js";
import {
IsArray,
IsInt,
IsNotEmpty,
IsString,
Min,
} from "class-validator";
import { BaseModel } from "../lib/fireclass.js";
@Collection("products")
export class Product extends BaseModel<Product> {
@IsString()
@IsNotEmpty()
name!: string;
@IsInt()
@Min(0)
stock!: number;
@IsArray()
@IsString({ each: true })
tags!: string[];
constructor(data?: Partial<Product>) {
super(data);
Object.assign(this, data);
}
}const product = new Product({
name: "Mechanical keyboard",
stock: -1,
tags: ["hardware"],
});
await product.save(); // throws ValidationFailedError; no write occursModels without class-validator decorators are valid. Fireclass does not require every field to carry a rule.
Use class-transformer's @Type with @ValidateNested so nested plain objects
become class instances before validation.
import { Collection } from "@dharayush7/fireclass-js";
import { Type } from "class-transformer";
import { IsString, ValidateNested } from "class-validator";
import { BaseModel } from "../lib/fireclass.js";
class Address {
@IsString()
city!: string;
}
@Collection("members")
export class Member extends BaseModel<Member> {
@ValidateNested()
@Type(() => Address)
address!: Address;
constructor(data?: Partial<Member>) {
super(data);
Object.assign(this, data);
}
}The transformation is used for validation. It does not alter the original model instance before Fireclass serializes it.
ValidationFailedError has a readable message and preserves the raw
ValidationError[] from class-validator.
import {
ValidationFailedError,
} from "@dharayush7/fireclass-js";
try {
await product.save();
} catch (error) {
if (error instanceof ValidationFailedError) {
for (const issue of error.errors) {
console.error(issue.property, issue.constraints);
}
}
throw error;
}Nested class-validator failures are available through each error's children
property. See Errors for application-level branching.
Validation runs on both creates and updates. Fireclass validates the entire current instance even though an existing document is written with merge semantics.
const product = await Product.findById("product_123");
if (product) {
product.stock = 12;
await product.save();
}This read-modify-save pattern preserves required model fields for validation.
Creating a partial instance with an existing id is appropriate only when the
model's validation rules also allow that partial shape.
findById, findMany, and findOne hydrate stored data without validation.delete, deleteById, and deleteMany do not validate documents.Load reflect-metadata before decorated models and enable decorator metadata:
import "reflect-metadata";{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}Install class-validator, class-transformer, and reflect-metadata alongside
the selected Fireclass runtime. The framework setup pages contain the complete
dependency commands.
Continue with Query Options to read validated models through typed filters.