Skip to content

$assert

The $assert tool provides type-safe validation using ArkType with detailed error reporting and standardized error codes. It's designed to validate data structures and return comprehensive error information when validation fails.

Features

  • Type-safe validation using ArkType validators
  • Detailed error reporting with specific error codes
  • Schema extraction for debugging and error messages
  • Integration with $code status codes
  • Result pattern for consistent error handling

API Reference

$assert(value, validator)

Validates a value against an ArkType validator and returns a Result.

Parameters:

  • val: T - The value to validate
  • validator: Type<unknown> - An ArkType validator/schema

Returns: Result<T> - Success with validated data or error with details

ts
import { type } from 'arktype'
import { $assert } from '#appkit/tools'

const userValidator = type({
  name: "string",
  email: "string.email",
  age: "number>=0"
})

const result = $assert(userData, userValidator)

if (result.success) {
  console.log('Valid user:', result.data)
} else {
  console.error('Validation error:', result.error)
  console.error('Expected schema:', result.context.expected)
  console.error('Received:', result.context.got)
}

Error Handling

The $assert function maps ArkType errors to specific validation error codes:

Error Code Mapping

ArkType ErrorValidation CodeDescription
patternvalidationPatternErrorString pattern/regex validation failed
union, unit, intersectionvalidationTypeErrorType mismatch errors
min, maxvalidationRangeErrorNumeric range validation failed
minLength, maxLength, exactLengthvalidationLengthErrorString/array length validation failed
requiredvalidationRequiredErrorRequired field is missing
domain, divisor, proto, before, after, predicatevalidationFormatErrorFormat/domain validation failed
Other errorsbadRequestGeneric validation error

Usage Examples

Basic Validation

ts
import { type } from 'arktype'
import { $assert } from '#appkit/tools'

// Simple string validation
const nameValidator = type("string>0")
const nameResult = $assert("John Doe", nameValidator)

// Email validation
const emailValidator = type("string.email")
const emailResult = $assert("user@example.com", emailValidator)

// Number range validation
const ageValidator = type("number>=18&<=120")
const ageResult = $assert(25, ageValidator)

Complex Object Validation

ts
const productValidator = type({
  id: "string",
  name: "string>0",
  price: "number>0",
  category: "'electronics' | 'books' | 'clothing'",
  "description?": "string",
  tags: "string[]",
  metadata: {
    weight: "number>0",
    dimensions: {
      width: "number>0",
      height: "number>0",
      depth: "number>0"
    }
  }
})

const productData = {
  id: "prod-123",
  name: "Wireless Headphones",
  price: 199.99,
  category: "electronics",
  tags: ["wireless", "bluetooth", "headphones"],
  metadata: {
    weight: 0.3,
    dimensions: {
      width: 15,
      height: 20,
      depth: 8
    }
  }
}

const result = $assert(productData, productValidator)

if (!result.success) {
  // Handle specific error types
  switch (result.code) {
    case $code.validationRequiredError:
      console.error('Missing required fields')
      break
    case $code.validationTypeError:
      console.error('Invalid data types')
      break
    case $code.validationRangeError:
      console.error('Values out of range')
      break
    default:
      console.error('Validation failed:', result.error)
  }
}

Error Context Usage

ts
const userValidator = type({
  username: "string>=3<=20",
  email: "string.email",
  age: "number>=13"
})

const invalidUser = {
  username: "ab", // too short
  email: "invalid-email", // invalid format
  age: 10 // too young
}

const result = $assert(invalidUser, userValidator)

if (!result.success) {
  console.log('Validation failed:', result.error)
  console.log('Expected schema:', result.context.expected)
  console.log('Received data:', result.context.got)
  console.log('Error code:', result.code)
}

Utility Functions

getValidationErrorCode(errors)

Maps ArkType errors to specific validation error codes.

Parameters:

  • errors: InstanceType<typeof arktype.errors> - ArkType validation errors

Returns: Specific $code error code

ts
import { getValidationErrorCode } from '#appkit/tools'
import { type } from 'arktype'

const validator = type("string.email")
const result = validator("invalid-email")

if (result instanceof type.errors) {
  const errorCode = getValidationErrorCode(result)
  console.log('Error code:', errorCode) // validationPatternError
}

getArkValidatorSchema(schema)

Extracts the expected schema structure from an ArkType validator for debugging.

Parameters:

  • schema: Type - ArkType validator

Returns: Schema structure object

ts
import { getArkValidatorSchema } from '#appkit/tools'
import { type } from 'arktype'

const validator = type({
  name: "string",
  age: "number"
})

const schema = getArkValidatorSchema(validator)
console.log(schema) // { name: "string", age: "number" }

Integration with Forms

The $assert tool works seamlessly with form validation:

ts
import { $assert } from '#appkit/tools'
import { type } from 'arktype'

const loginValidator = type({
  email: "string.email",
  password: "string>=8"
})

async function handleLogin(formData: unknown) {
  const validation = $assert(formData, loginValidator)
  
  if (!validation.success) {
    // Return user-friendly error messages based on error code
    switch (validation.code) {
      case $code.validationPatternError:
        return { error: 'Please enter a valid email address' }
      case $code.validationLengthError:
        return { error: 'Password must be at least 8 characters' }
      case $code.validationRequiredError:
        return { error: 'All fields are required' }
      default:
        return { error: 'Please check your input and try again' }
    }
  }
  
  // Proceed with validated data
  const { email, password } = validation.data
  // ... login logic
}

Best Practices

  1. Create Reusable Validators: Define common validators as constants
  2. Handle Specific Error Codes: Use the error code mapping for user-friendly messages
  3. Use Context Information: Leverage the expected/got context for debugging
  4. Type Safety: Let TypeScript infer the validated type from the validator
  5. Error Boundaries: Implement proper error handling for validation failures
  • $code: Status codes used for error reporting
  • Result: Result pattern used by $assert
  • ArkType: External validation library used for schema definition