Master Data Validation in Node.js with Joi: A Clean, Code-Free Approach
Learn how to efficiently validate user input in Node.js using the powerful Joi library, covering schema definitions, conditional rules, handling unknown fields, and integrating validation into Hapi routes, with clear code examples that replace cumbersome if‑else checks.
When building Node.js applications, validating user input is essential but can become cumbersome. Joi, the validation module bundled with Hapi, provides a highly readable and maintainable way to define validation rules without writing extensive if‑else logic.
Defining a Validation Schema
var Joi = require('joi');
var schema = Joi.object({
username: Joi.string().min(3).max(30).required(),
isA: Joi.boolean(),
AVal: Joi.number(),
isB: Joi.boolean(),
BVal: Joi.string()
})
.with('isA', 'AVal')
.with('isB', 'BVal')
.without('isA', 'isB')
.or('isA', 'isB');The schema means:
username : a required string between 3 and 30 characters.
isA and isB : optional booleans indicating which login method is used.
AVal and BVal : values required when their corresponding flags are true. with('isA', 'AVal') and with('isB', 'BVal') enforce that if isA (or isB) is present, the matching value must also be provided. without('isA', 'isB') ensures the two flags are mutually exclusive. or('isA', 'isB') requires at least one of them to be present.
Basic Validation Examples
var input = { username: 'zzbo' };
var output = Joi.validate(input, schema);
// ValidationError: "value" must contain at least one of [isA, isB]Missing both isA and isB triggers an error.
var input = { username: 'zzbo', isA: true };
var output = Joi.validate(input, schema);
// ValidationError: "isA" missing required peer "AVal"Providing isA without AVal also fails.
var input = { username: 'zzbo', isA: true, AVal: 666666 };
var output = Joi.validate(input, schema);
// null (validation passes)When all required fields are present, validation succeeds.
Using Joi Outside a Schema Object
Joi.string().validate(666666); // ValidationError: "value" must be a string
Joi.string().validate('hehe'); // passesYou can also allow unknown fields or enable allowUnknown:
Joi.validate({y: 3}, {x: Joi.string()}); // ValidationError: "y" is not allowed
Joi.validate({y: 3}, {x: Joi.string()}, {allowUnknown: true}); // passesValidating Functions and Complex Types
var myObject = { a: 123, b: function () {} };
var schema = { a: Joi.number().integer(), b: Joi.func() };
Joi.validate(myObject, schema); // passesJoi also supports any, array, boolean, date, func, number, object, and string types.
Advanced Rules
Combining numbers with specific strings:
Joi.number().allow('a').validate('a'); // passes
Joi.number().valid('a').validate('a'); // passes
Joi.number().valid(['a', 'b']).validate('b'); // passes
Joi.number().allow('a').validate(3); // passesDisallowing a specific value:
Joi.number().invalid(5).validate(5); // errorAllowing any type:
Joi.any().validate(); // passesValidating nested objects:
var Joi = require('joi');
var schemeAB = Joi.object({ A: Joi.string().required(), B: Joi.string().required() });
var schemeCD = Joi.object({ C: Joi.string().required(), D: schemeAB });
var output = Joi.validate({ C: 'hehe', D: { A: 'haha', B: 'hoho' } }, schemeCD);
console.log(output); // passesUsing Joi with Hapi
var Hapi = require('hapi');
var Joi = require('Joi');
var server = new Hapi.Server();
server.connection({ port: 8000 });
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
if (request.query.hour && request.query.minute) {
reply(request.query.hour + ':' + request.query.minute);
} else {
reply('time unknown');
}
},
config: {
validate: {
query: {
hour: Joi.number().min(0).max(23),
minute: Joi.number().min(0).max(59)
}
}
}
});
server.start(function (err) {
if (err) throw err;
console.log('Server running...');
});Accessing http://127.0.0.1:8000/?hour=2&minute=3 returns 2:3, while an out‑of‑range minute triggers a validation error.
Conclusion
Try Joi yourself to experience how declarative schemas can replace verbose conditional checks and make data validation both readable and maintainable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
