Logo
⚠️ Unsaved
[M]:

Building Complex Schemas with Joi

This notebook explores advanced techniques for building complex validation schemas with Joi, the powerful schema validation library for JavaScript. We'll cover nested objects, conditional validation, custom validators, and more to help you implement robust data validation in your Node.js applications.

[22]:
$ npm install joi

up to date in 425ms

28 packages are looking for funding
  run `npm fund` for details
[23]:
Joi version: 17.13.3 
[M]:

1. Nested Object Schemas

Complex data often involves nested objects. Let's see how to validate them effectively.

[24]:
[25]:
[26]:
[27]:
Nested object validation result:
{
  value: {
    id: '123e4567-e89b-12d3-a456-426614174000',
    username: 'johndoe',
    name: { first: 'John', middle: '', last: 'Doe' },
    contact: { email: 'john.doe@example.com', phone: '555-123-4567' },
    addresses: { home: [Object], shipping: [Object] }
  },
  error: [Error [ValidationError]: "id" must be a valid GUID] {
    _original: {
      id: '123e4567-e89b-12d3-a456-426614174000',
      username: 'johndoe',
      name: [Object],
      contact: [Object],
      addresses: [Object]
    },
    details: [ [Object] ]
  }
} 
[M]:

2. Conditional Validation

Sometimes validation rules depend on other fields. Let's explore conditional validation.

[28]:
[29]:
Credit card payment validation:
{
  value: {
    method: 'credit_card',
    cardNumber: '4111111111111111',
    expiryMonth: 12,
    expiryYear: 2026,
    cvv: '123'
  }
} 
[30]:
PayPal payment validation:
{ value: { method: 'paypal', paypalEmail: 'user@example.com' } } 
[31]:
Invalid payment validation:
{
  value: { method: 'credit_card', paypalEmail: 'user@example.com' },
  error: [Error [ValidationError]: "cardNumber" is required] {
    _original: { method: 'credit_card', paypalEmail: 'user@example.com' },
    details: [ [Object] ]
  }
} 
[M]:

3. Complex Array Validation

Let's explore validating arrays with complex items and constraints.

[32]:
[33]:
[34]:
Complex order validation result:
{
  value: {
    orderId: '123e4567-e89b-12d3-a456-426614174000',
    customerId: 'cust-12345',
    items: [ [Object], [Object] ],
    shippingAddress: {
      street: '123 Main St',
      city: 'Anytown',
      state: 'CA',
      zipCode: '12345'
    },
    paymentMethod: {
      method: 'credit_card',
      cardNumber: '4111111111111111',
      expiryMonth: 12,
      expiryYear: 2026,
      cvv: '123'
    }
  },
  error: [Error [ValidationError]: "orderId" must be a valid GUID] {
    _original: {
      orderId: '123e4567-e89b-12d3-a456-426614174000',
      customerId: 'cust-12345',
      items: [Array],
      shippingAddress: [Object],
      paymentMethod: [Object]
    },
    details: [ [Object] ]
  }
} 
Calculated total: undefined 
[M]:

4. Dynamic Keys with Pattern Validation

Sometimes you need to validate objects with dynamic keys.

[35]:
[36]:
[37]:
Content with dynamic metadata validation:
{
  value: {
    id: 'article-123',
    title: 'Understanding Joi Validation',
    content: 'Joi is a powerful schema validation library...',
    type: 'article',
    metadata: {
      author: 'John Doe',
      published_date: '2023-05-15',
      read_time: 5,
      tags: [Array],
      featured: true,
      category: 'programming'
    }
  }
} 
[38]:
Invalid metadata validation:
{
  value: {
    id: 'article-456',
    title: 'Invalid Metadata Example',
    content: 'This example has invalid metadata...',
    type: 'article',
    metadata: {
      author: 'Jane Smith',
      '1invalid_key': 'This key starts with a number',
      tags: [Array]
    }
  },
  error: [Error [ValidationError]: "metadata.1invalid_key" is not allowed] {
    _original: {
      id: 'article-456',
      title: 'Invalid Metadata Example',
      content: 'This example has invalid metadata...',
      type: 'article',
      metadata: [Object]
    },
    details: [ [Object] ]
  }
} 
[M]:

5. Interdependent Fields

Let's validate fields that depend on each other.

[39]:
[40]:
Date range validation (without duration):
{
  value: {
    startDate: 2023-01-01T00:00:00.000Z,
    endDate: 2023-01-05T00:00:00.000Z,
    duration: 4
  }
} 
[41]:
Date range validation (with correct duration):
{
  value: {
    startDate: 2023-02-10T00:00:00.000Z,
    endDate: 2023-02-15T00:00:00.000Z,
    duration: 5
  }
} 
[42]:
Date range validation (with incorrect duration):
{
  value: {
    startDate: 2023-03-20T00:00:00.000Z,
    endDate: 2023-03-25T00:00:00.000Z,
    duration: 10
  },
  error: [Error [ValidationError]: Error code "dateRange.durationMismatch" is not defined, your custom type is missing the correct messages definition] {
    _original: { startDate: '2023-03-20', endDate: '2023-03-25', duration: 10 },
    details: [ [Object] ]
  }
} 
[M]:

Summary

This notebook has demonstrated advanced techniques for building complex schemas with Joi:

  1. Nested Object Schemas: Creating reusable schema components and composing them into complex structures
  2. Conditional Validation: Implementing validation rules that depend on other fields
  3. Complex Array Validation: Validating arrays with complex item schemas and constraints
  4. Dynamic Keys with Pattern Validation: Validating objects with dynamic keys that follow specific patterns
  5. Interdependent Fields: Validating fields that depend on each other's values

These techniques enable you to build robust validation for even the most complex data structures in your JavaScript applications.

For more information, check out the Joi documentation.

Sign in to save your work and access it from anywhere