ExisJS

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)

src/http/users/route.ts
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

src/http/users/route.ts
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 (allows undefined).
  • coerce: Instructs the Rust engine to automatically convert types when possible before validating. For example, converting "123" into a number, or 3000 into 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.

env.ts
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)