Free & open source — no account required
Free & open source — no account required
This technical guide provides an in-depth analysis of the json to joi engine, best practices for implementation, and data security standards.
Joi is the validation library of the Hapi.js ecosystem, but it's widely used in Express, Fastify, and NestJS projects for validating request bodies, query parameters, and environment variables. Unlike Yup (which targets browser form validation), Joi is built for server-side use: synchronous by default, optimized for strict API input validation, and designed to produce structured error objects that are easy to return as API responses.
// Input JSON (sample request body)
{
"username": "dev_guru",
"email": "dev@example.com",
"age": 28,
"role": "editor",
"website": "https://devguru.io",
"bio": null,
"preferences": {
"theme": "dark",
"notifications": true
}
}
// Generated Joi Schema
import Joi from 'joi';
export const rootPreferencesJoiSchema = Joi.object({
theme: Joi.string().required(),
notifications: Joi.boolean().required(),
});
export const rootJoiSchema = Joi.object({
username: Joi.string().required(),
email: Joi.string().email().required(),
age: Joi.number().required(),
role: Joi.string().valid("editor").required(),
website: Joi.string().uri().required(),
bio: Joi.string().allow(null),
preferences: rootPreferencesJoiSchema.required(),
});
import Joi from 'joi';
const createUserSchema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(20)
.required()
.messages({
'string.alphanum': 'Username may only contain letters and numbers',
'string.min': 'Username must be at least 3 characters',
'any.required': 'Username is required',
}),
email: Joi.string().email({ tlds: { allow: false } }).required(),
password: Joi.string().min(8).required(),
role: Joi.string()
.valid('user', 'editor', 'admin')
.default('user'),
age: Joi.number().integer().min(13).max(120).required(),
website: Joi.string().uri().allow(null, '').optional(),
// Conditional: bio required only if role is 'editor'
bio: Joi.when('role', {
is: 'editor',
then: Joi.string().min(10).required(),
otherwise: Joi.string().optional(),
}),
});
import express, { Request, Response, NextFunction } from 'express';
import Joi from 'joi';
// Reusable validation middleware factory
function validate(schema: Joi.ObjectSchema) {
return (req: Request, res: Response, next: NextFunction) => {
const { error, value } = schema.validate(req.body, {
abortEarly: false, // collect ALL errors, not just the first
stripUnknown: true, // remove fields not in schema
convert: true, // coerce types (e.g. "28" → 28)
});
if (error) {
return res.status(400).json({
status: 'error',
errors: error.details.map(d => ({
field: d.path.join('.'),
message: d.message,
})),
});
}
req.body = value; // use the validated + coerced value
next();
};
}
const router = express.Router();
router.post('/users', validate(createUserSchema), async (req, res) => {
// req.body is now typed and validated
const user = await db.users.create(req.body);
res.status(201).json(user);
});
.test(async () => {})). Joi's schema.validateAsync() also supports async, but the sync schema.validate() is the common path for request validation.ValidationError with a details array. Yup returns a ValidationError with an errors array. Both are structured for easy API response formatting.z.infer<> is the strongest option.What does abortEarly: false do? By default, Joi stops at the first validation error. Setting abortEarly: false collects all errors before returning — essential for form-like API responses where you want to show all problems at once.
What's the difference between .allow(null) and .optional()? .allow(null) accepts the value null explicitly. .optional() allows the key to be absent from the object. A field can be both: Joi.string().allow(null).optional() accepts null, a string, or the key being missing entirely.
Does it work with NestJS? Yes. NestJS's ValidationPipe uses class-validator by default, but you can swap in Joi using the joiSchema option or a custom pipe that calls schema.validate().
Is my JSON sent to a server? No. TypeMorph runs entirely in your browser — none of your data leaves your machine.
Is the processing local-only?
Absolutely. TypeMorph operates entirely within your browser's sandbox. We use Web Workers for high-performance computation without ever transmitting your JSON, SQL, or API data to a remote server.
Can I use this for enterprise projects?
Yes. The tool is designed for professional software engineers who require GDPR compliance and data privacy. It is trusted by developers at top-tier startups and financial institutions.