
This notebook introduces Joi, a powerful schema validation library for JavaScript. We'll explore how to use Joi to validate objects, forms, API payloads, and configuration data with simple, readable validation rules.
$ npm install joi added 6 packages in 7s 28 packages are looking for funding run `npm fund` for details
Joi version: 17.13.3
Let's start with some basic validation examples to understand how Joi works. Joi allows you to define schemas that describe the shape of your data.
Valid user validation result:
{
value: {
username: 'johndoe',
email: 'john@example.com',
birthYear: 1990,
password: 'password123'
}
}
Invalid user validation result:
{
value: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
error: [Error [ValidationError]: "username" length must be at least 3 characters long] {
_original: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
details: [ [Object] ]
}
}
Joi provides several options to customize the validation behavior.
Strict validation (default):
{
value: {
name: 'Jane Smith',
age: 28,
email: 'jane@example.com',
favoriteColor: 'blue',
address: {
street: '123 Main St',
city: 'Anytown',
zipCode: '12345',
country: 'USA'
}
},
error: [Error [ValidationError]: "address.country" is not allowed] {
_original: {
name: 'Jane Smith',
age: 28,
email: 'jane@example.com',
favoriteColor: 'blue',
address: [Object]
},
details: [ [Object] ]
}
}
Validation with allowUnknown: true:
{
value: {
name: 'Jane Smith',
age: 28,
email: 'jane@example.com',
favoriteColor: 'blue',
address: {
street: '123 Main St',
city: 'Anytown',
zipCode: '12345',
country: 'USA'
}
}
}
Validation with stripUnknown: true:
{
value: {
name: 'Jane Smith',
age: 28,
email: 'jane@example.com',
address: { street: '123 Main St', city: 'Anytown', zipCode: '12345' }
}
}
Validation with abortEarly: true (default):
{
value: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
error: [Error [ValidationError]: "name" is required] {
_original: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
details: [ [Object] ]
}
}
Validation with abortEarly: false:
{
value: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
error: [Error [ValidationError]: "name" is required. "email" must be a valid email. "username" is not allowed. "birthYear" is not allowed. "password" is not allowed] {
_original: {
username: 'j',
email: 'not-an-email',
birthYear: 1800,
password: 'pw'
},
details: [ [Object], [Object], [Object], [Object], [Object] ]
}
}
Joi provides a rich set of validation rules for different data types.
Joi allows you to create schemas with conditional validation logic.
Personal account validation result:
{
value: {
username: 'johndoe',
password: 'password123',
accountType: 'personal'
}
}
Business account validation result:
{
value: {
username: 'acmecorp',
password: 'securepass123',
accountType: 'business',
companyName: 'ACME Corporation',
taxId: '123-45-6789'
}
}
Invalid business account validation result:
{
value: {
username: 'acmecorp',
password: 'securepass123',
accountType: 'business'
},
error: [Error [ValidationError]: "companyName" is required. "taxId" is required] {
_original: {
username: 'acmecorp',
password: 'securepass123',
accountType: 'business'
},
details: [ [Object], [Object] ]
}
}
Joi allows you to customize error messages for better user experience.
Signup validation with custom messages:
{
value: { username: 'a', email: 'not-an-email', password: 'weak' },
error: [Error [ValidationError]: Username must be at least 3 characters long. Please enter a valid email address. Password must be at least 8 characters long. Password must contain at least one uppercase letter, one lowercase letter, and one number] {
_original: { username: 'a', email: 'not-an-email', password: 'weak' },
details: [ [Object], [Object], [Object], [Object] ]
}
}
Formatted errors for UI display:
{
username: 'Username must be at least 3 characters long',
email: 'Please enter a valid email address',
password: 'Password must contain at least one uppercase letter, one lowercase letter, and one number'
}
Let's see how Joi can be used to validate API requests in a real-world scenario.
Validated API request:
{
query: { page: 2, limit: 20, sort: 'desc', filter: 'published' },
body: {
title: 'Understanding Joi Validation',
content: 'Joi is a powerful schema validation library for JavaScript...',
tags: [ 'javascript', 'validation', 'nodejs' ],
published: true,
authorId: '507f1f77bcf86cd799439011'
},
params: { id: '507f1f77bcf86cd799439011' },
headers: {
'content-type': 'application/json',
authorization: 'Bearer token123'
}
}
Invalid API request validation result:
[
{
message: '"page" must be greater than or equal to 1',
path: [ 'page' ],
type: 'number.min',
context: { limit: 1, value: 0, label: 'page', key: 'page' }
},
{
message: '"limit" must be less than or equal to 100',
path: [ 'limit' ],
type: 'number.max',
context: { limit: 100, value: 200, label: 'limit', key: 'limit' }
},
{
message: '"sort" must be one of [asc, desc]',
path: [ 'sort' ],
type: 'any.only',
context: { valids: [Array], label: 'sort', value: 'invalid', key: 'sort' }
}
]
Joi is great for validating environment variables and configuration objects.
Validated environment configuration:
{
NODE_ENV: 'production',
PORT: 8080,
DATABASE_URL: 'mongodb://localhost:27017/myapp',
API_KEY: 'secret-api-key-123',
LOG_LEVEL: 'warn',
ENABLE_CACHE: true,
CORS_ORIGINS: [ 'example.com', 'api.example.com' ],
CACHE_TTL: 300
}
ENABLE_CACHE type: boolean
CACHE_TTL (default): 300
Joi allows you to create custom validation functions for complex validation logic.
Valid order validation result:
{
value: {
customerId: 'cust123',
items: [ [Object], [Object] ],
total: 46.97
}
}
Invalid order validation result:
{
value: { customerId: 'cust123', items: [ [Object], [Object] ], total: 50 },
error: [Error [ValidationError]: Error code "order.invalidTotal" is not defined, your custom type is missing the correct messages definition] {
_original: { customerId: 'cust123', items: [Array], total: 50 },
details: [ [Object] ]
}
}
Let's look at some performance considerations when using Joi.
Here are some practical tips for using Joi effectively in your projects.
Reusable schema components:
{
type: 'object',
keys: {
id: { type: 'string', rules: [Array] },
email: { type: 'string', flags: [Object], rules: [Array] },
password: { type: 'string', flags: [Object], rules: [Array] },
phone: { type: 'string', flags: [Object], rules: [Array] }
}
}
Schema description:
{
"type": "object",
"keys": {
"username": {
"type": "string",
"flags": {
"presence": "required"
},
"rules": [
{
"name": "alphanum"
},
{
"name": "min",
"args": {
"limit": 3
}
},
{
"name": "max",
"args": {
"limit": 30
}
}
]
},
"email": {
"type": "string",
"flags": {
"presence": "required"
},
"rules": [
{
"name": "email"
}
]
},
"birthYear": {
"type": "number",
"rules": [
{
"name": "integer"
},
{
"name": "min",
"args": {
"limit": 1900
}
},
{
"name": "max",
"args": {
"limit": 2023
}
}
]
},
"password": {
"type": "string",
"rules": [
{
"name": "pattern",
"args": {
"regex": "/^[a-zA-Z0-9]{3,30}$/"
}
}
]
}
}
}
Express validation middleware created
This notebook has introduced Joi, a powerful schema validation library for JavaScript. We've covered:
allowUnknown and stripUnknownJoi is a versatile tool that can help ensure data integrity in your applications. It's particularly useful for:
For more information, check out the Joi documentation.