Validation (tex)
ExisJS ships with a efficient, integrated validation library out of the box, exposed as tex from exisjs/validator. It is powered by a efficient Rust engine, fully isomorphic, and deeply integrated with TypeScript and OpenAPI (Swagger).
Core Types
The tex object provides factory functions for every common primitive and data structure.
tex.string(): Validates a string.tex.number(): Validates a number.tex.boolean(): Validates a boolean.tex.email(): Validates standard email formatting.tex.enum(['A', 'B']): Validates against a specific set of allowed strings.
Objects & Arrays
tex.object({ ... }): Validates an object against a strict shape.tex.array(schema): Validates an array of items matching the given schema.
const UserProfile = tex.object({ id: tex.string(), tags: tex.array(tex.string()), role: tex.enum(['admin', 'user'])})Usage in Routes
ExisJS tightly integrates the tex validator directly into its routing layer, providing immediate TypeScript inference for ctx.body, @Body(), and other parameters.
Class-Based (OOP)
import { Controller, Post, Body } from 'exisjs/decorators'import { tex } from 'exisjs/validator'
const CreateUserSchema = tex.object({ email: tex.email() })
@Controller('/users')export default class UserController { @Post('/', { body: CreateUserSchema }) createUser(@Body() body: any) { return { success: true, email: body.email } }}Functional
import { controller, route } from 'exisjs/router'import { tex } from 'exisjs/validator'
const CreateUserSchema = tex.object({ email: tex.email() })
export default controller({ createUser: route.post('/users', { body: CreateUserSchema, async handle(ctx) { // ctx.body is strictly inferred as { email: string } return { success: true, email: ctx.body.email } } })})Type Options
All validators accept an options object that allows you to configure validation constraints and behaviors.
optional: Marks the field as optional (allowsundefined).coerce: Instructs the Rust engine to automatically convert types when possible before validating. For example, converting"123"into a number, or3000into a string.
// Type Conversion Examples using { coerce: true }const EnvSchema = tex.object({ // Converts string "3000" from process.env to number 3000 PORT: tex.number({ coerce: true }), // Converts boolean 'false' or number '0' to string "false" / "0" ID_AS_STRING: tex.string({ coerce: true }),
// Converts string "true" or number '1' to boolean true ENABLE_FEATURE: tex.boolean({ coerce: true })})String Options
min: Enforces a minimum string length.max: Enforces a maximum string length.
Number Options
min: Enforces a minimum numeric value.max: Enforces a maximum numeric value.
const User = tex.object({ id: tex.string(), email: tex.email(), password: tex.string({ min: 8, max: 100 }), age: tex.number({ min: 13, optional: true })})Custom Data Manipulation
.sanitize(...fns)
Runs one or more synchronous sanitization functions over the data before the Rust validation executes. Use this for complex object transformations or string formatting. ExisJS provides a rich suite of built-in sanitizers through the exisjs/sanitize module.
import { sanitize } from 'exisjs/sanitize'
// Built-in sanitizationconst CleanString = tex.string().sanitize(sanitize.trim, sanitize.toLowerCase)
// Custom data transformationconst WhiteListIPs = tex.array(tex.string()) .sanitize((val) => typeof val === 'string' ? val.split(',') : val).refine(fn, message)
Runs custom validation logic after the Rust validation executes. Useful for complex business logic that cannot be expressed purely with basic schema types.
const PasswordConfirm = tex.object({ password: tex.string(), confirm: tex.string()}).refine((data) => data.password === data.confirm, "Passwords must match")Type Inference
You can extract the raw TypeScript interface directly from any schema using the ResolveSchema utility.
import { tex, type ResolveSchema } from 'exisjs/validator'
const ProfileSchema = tex.object({ name: tex.string(), age: tex.number({ optional: true })})
// Resolves to: { name: string; age?: number | undefined }type Profile = ResolveSchema<typeof ProfileSchema>OpenAPI Generation
The TexEngine automatically converts validation schemas into strictly compliant OpenAPI/Swagger JSON schemas when attached to routes. This powers zero-config Swagger documentation once @exisjs/swagger is added.
Environment Validation
You can safely parse and validate your environment variables at startup using the standard .parse() method.
import { tex } from 'exisjs/validator'
// Validates process.env synchronously. Crashes the app on boot with a // beautiful error message if validation fails.export const env = tex.object({ PORT: tex.number({ coerce: true, optional: true }), DATABASE_URL: tex.string(), JWT_SECRET: tex.string({ min: 32 })}).parse(process.env)