Validation
Every model exposes validate() (throws on failure) and check()(returns error map or null). Validation rules are defined per-field using FieldRules<T>.
validate() — throws ValidationError
// model.validate(data, rules)
// Throws ValidationError if any rule fails
try {
await User.validate(
{ email: 'not-an-email', name: '', password: 'abc' },
{
email: { required: true, email: true },
name: { required: true, minLength: 2 },
password: { required: true, minLength: 8 },
}
);
} catch (err) {
if (err instanceof ValidationError) {
console.log(err.message); // "Validation failed"
console.log(err.errors); // { email: "Invalid email", password: "Min length is 8" }
}
}check() — returns error map
// model.check(data, rules)
// Returns Record<string, string> | null (null = valid)
const errors = await User.check(
{ email: 'joe@example.com', name: 'Joe', password: 'securepass' },
{
email: { required: true, email: true },
name: { required: true, minLength: 2, maxLength: 100 },
password: { required: true, minLength: 8 },
}
);
if (errors) {
// Return errors to client
return res.status(400).json({ errors });
}
// No errors — proceed to insertFieldRules reference
All rules example
// FieldRules<T> — all available rule keys
const rules = {
email: {
required: true, // field must be present and non-empty
email: true, // must match email pattern
},
username: {
required: true,
minLength: 3, // string min length
maxLength: 30, // string max length
match: /^[a-z0-9_]+$/, // must match regex
},
age: {
required: true,
min: 18, // numeric minimum
max: 120, // numeric maximum
},
bio: {
maxLength: 500, // optional but max length if present
},
referralCode: {
custom: async (value, row) => {
// Return an error string, or null/undefined if valid
const exists = await Referral.exists({ code: value });
return exists ? null : 'Invalid referral code';
},
},
};Custom validators
// Custom validator function
// (value: unknown, row: Partial<T>) => string | null | Promise<string | null>
const rules = {
email: {
required: true,
email: true,
custom: async (value) => {
const taken = await User.exists({ email: value as string });
return taken ? 'Email already in use' : null;
},
},
username: {
required: true,
custom: (value) => {
const reserved = ['admin', 'root', 'system'];
return reserved.includes(value as string)
? 'Username is reserved'
: null;
},
},
};In a Next.js API route
app/api/users/route.ts
// app/api/users/route.ts — using check() in a Next.js API route
import { NextRequest, NextResponse } from 'next/server';
import { User } from '@/db';
import { ValidationError } from 'slintorm';
export async function POST(req: NextRequest) {
const body = await req.json();
const errors = await User.check(body, {
email: { required: true, email: true },
name: { required: true, minLength: 2 },
password: { required: true, minLength: 8 },
});
if (errors) {
return NextResponse.json({ errors }, { status: 422 });
}
const user = await User.insert({
email: body.email,
name: body.name,
password: body.password,
});
return NextResponse.json({ id: user.id }, { status: 201 });
}