SlintORM
Docsnpm

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 insert

FieldRules reference

RuleTypeDescription
requiredbooleanField must be present and non-empty
emailbooleanMust be a valid email address
minLengthnumberString must be at least N characters
maxLengthnumberString must be at most N characters
minnumberNumeric value must be >= N
maxnumberNumeric value must be <= N
matchRegExpValue must match the regular expression
custom(value, row) => string | nullCustom validator. Return error string or null. Async supported.

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 });
}
PreviousSoft DeleteNextHooks