Gubu: Object Shape Validation Utility

9.0.0 · active · verified Sun Apr 19

Gubu is an object shape validation utility for JavaScript and TypeScript, designed to provide a more intuitive and less verbose developer experience compared to alternatives like Joi or JSON-Schema. Currently stable at version 9.0.0, the library differentiates itself with a "Schema By Example" approach, where validation schemas closely mirror the actual data structure. This design simplifies reading and reasoning about validation rules. A key feature is its ability to deeply fill out objects with default values if properties are missing, differing from shallow merge operations like `Object.assign`. It's crucial for developers to note that Gubu deliberately mutates the input object to inject these defaults, a design choice to simplify internal logic and delegate cloning decisions to the calling code. Gubu functions effectively in both browser and Node.js environments and ships with full TypeScript support.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates defining a Gubu schema with optional fields (having defaults), required fields (using type constructors like `Boolean`), array validation, and deep object merging. It also showcases how Gubu mutates the input object and catches various validation errors.

import { Gubu } from 'gubu' // Using ESM syntax for modern projects

const optionsShape = Gubu({
  server: {
    port: 8080,        // Default 8080, optional
    host: 'localhost', // Default 'localhost', optional
    secure: Boolean    // Required boolean, no default
  },
  client: {
    timeout: Number,   // Required number, no default
    debug: Boolean,    // Required boolean, no default
    headers: [String], // Array of strings, optional, empty array default if not provided
    retries: 3         // Default 3, optional
  },
  plugins: [            // Array of objects, optional, empty array default
    { 
      name: String,     // Required string
      enabled: Boolean  // Required boolean
    }
  ]
})

console.log('--- Scenario 1: Empty input, check defaults and required fields ---')
let config1 = {}
try {
  optionsShape(config1) // Mutates config1
  console.log('Validated Config 1:', JSON.stringify(config1, null, 2))
} catch (e: any) {
  console.error('Validation Error 1:', e.message)
}

console.log('\n--- Scenario 2: Partial input, check deep merging and specific values ---')
let config2 = {
  server: {
    port: 9000,
    secure: true
  },
  client: {
    timeout: 5000,
    debug: false,
    headers: ['X-Custom-Header-A']
  }
}
try {
  optionsShape(config2) // Mutates config2
  console.log('Validated Config 2:', JSON.stringify(config2, null, 2))
} catch (e: any) {
  console.error('Validation Error 2:', e.message)
}

console.log('\n--- Scenario 3: Invalid input type for a field ---')
let config3 = {
  server: {
    port: 'not-a-number', // Invalid type
    secure: true
  },
  client: {
    timeout: 1000,
    debug: true,
    headers: []
  }
}
try {
  optionsShape(config3)
  console.log('Validated Config 3:', JSON.stringify(config3, null, 2))
} catch (e: any) {
  console.error('Validation Error 3:', e.message)
}

console.log('\n--- Scenario 4: Missing a required field ---')
let config4 = {
  server: {
    port: 8080,
    // secure is missing
  },
  client: {
    timeout: 1000,
    debug: true,
    headers: []
  }
}
try {
  optionsShape(config4)
  console.log('Validated Config 4:', JSON.stringify(config4, null, 2))
} catch (e: any) {
  console.error('Validation Error 4:', e.message)
}

view raw JSON →