Skip to content

Validation ​

With rules ​

ts
import { required, email, min, max, length, match, integer } from '@risklight/models'

class User extends Model {
  validation() {
    return {
      name:  required.and(length(2, 50)),
      email: required.and(email),
      age:   required.and(integer).and(min(18)),
      phone: match(/^\+\d{10,15}$/),
    }
  }
}

const user = new User()
const errors = await user.validate()
// { name: 'Required', email: 'Required', age: 'Required' }

With Zod ​

Zod schemas take priority over validation() rules:

ts
import { z } from 'zod'

class User extends Model {
  defaults() { return { name: '', email: '' } }
  schema() {
    return z.object({
      name: z.string().min(2),
      email: z.string().email(),
    })
  }
}

Rule combinators ​

ts
// AND — both must pass
required.and(email)

// OR — at least one must pass
required.or(email)

// Custom message
required.format('This field cannot be empty')

Available rules ​

RuleDescription
requiredNot null/undefined/empty
emailValid email
urlValid URL
uuidValid UUID
integerInteger number
numericNumber or numeric string
booleanBoolean value
stringString value
arrayArray value
objectPlain object
min(n)Number >= n
max(n)Number <= n
between(a, b)Number between a and b
gt(n), gte(n), lt(n), lte(n)Comparisons
length(min, max?)String/array length
match(regex)Matches pattern
equals(value)Strictly equal
dateValid date
after(date), before(date)Date comparisons
alpha, alphanumericLetter/number only
ip, iso8601, base64, asciiFormat checks
creditcardLuhn algorithm check
jsonValid JSON string
positive, negativeSign checks
not(...values)Exclusion
same(attr)Same as another attribute

Localization ​

ts
import { register, locale } from '@risklight/models'

register('de', {
  required: 'Pflichtfeld',
  email:    'Ungueltige E-Mail',
})

locale('de')

Backend validation (422) ​

When the server returns 422, errors are automatically parsed into model.errors:

ts
try {
  await user.save()
} catch (e) {
  console.log(user.errors)
  // { name: ['Name is required'], email: ['Invalid email'] }
}

Error handling ​

ts
import { ValidationError, RequestError, ResponseError } from '@risklight/models'

try {
  await user.save()
} catch (e) {
  if (e instanceof ValidationError) {
    // Client-side validation failed
    console.log(e.getValidationErrors())
  }
  if (e instanceof ResponseError) {
    // Server returned error (e.g. 422)
    console.log(e.getResponse()?.getStatus())
  }
  if (e instanceof RequestError) {
    // Network/request error
    console.log(e.getError())
  }
}

Released under the MIT License.