I have been using Joi library for validation user inputs like this.
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required()
});
const validationResult = await schema.validateAsync({ username: 'a' }, { abortEarly: false, warnings: true });
This works fine, the problem is later in code I would want to use this validation again. But the warning messages are still in the local context.
And if I input he { username: 'ba'} the error message will still display that min length of "a" needs to be 3.
Do you know how can I use the schema object again, and strip the local warnings context.
Validation context in Joi can carry over between validations when reusing the same schema instance. Try these two approaches and see if it solves the problem:
Create fresh schema clone for each validation:
const baseSchema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required()
});
// Use schema.clone() for each validation
const validationResult1 = await baseSchema.clone().validateAsync({ username: 'a' });
const validationResult2 = await baseSchema.clone().validateAsync({ username: 'ba' });
Create a validation function that always uses a fresh schema:
const validateUsername = async (data) => {
const schema = Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required()
});
return await schema.validateAsync(data, { abortEarly: false, warnings: true });
};
// Use it multiple times
try {
await validateUsername({ username: 'a' });
await validateUsername({ username: 'ba' });
} catch (err) {
console.error(err);
}
The second approach is generally preferred because:
I hope this helps
You're caching the schema in a Map but still running into the same context persistence issue. The solution below allows for efficient caching while avoiding the context issue.
const Joi = require('joi');
// Create a schema cache using Map
class ValidationSchemaCache {
constructor() {
this.schemaCache = new Map();
}
getSchema(schemaName) {
if (!this.schemaCache.has(schemaName)) {
// Define your schemas here
const schemas = {
'user': Joi.object({
username: Joi.string()
.alphanum()
.min(3)
.max(30)
.required()
})
// Add other schemas as needed
};
const schema = schemas[schemaName];
if (!schema) {
throw new Error(`Schema ${schemaName} not found`);
}
this.schemaCache.set(schemaName, schema);
}
// Return a clone of the cached schema
return this.schemaCache.get(schemaName).clone();
}
async validate(schemaName, data, options = { abortEarly: false, warnings: true }) {
const schema = this.getSchema(schemaName);
return await schema.validateAsync(data, options);
}
}
// Usage example:
const validationCache = new ValidationSchemaCache();
async function test() {
try {
// First validation
const result1 = await validationCache.validate('user', { username: 'a' });
console.log('Result 1:', result1);
} catch (err1) {
console.error('Error 1:', err1.details);
}
try {
// Second validation with different data
const result2 = await validationCache.validate('user', { username: 'ba' });
console.log('Result 2:', result2);
} catch (err2) {
console.error('Error 2:', err2.details);
}
}
test();
What I’ve done here is:
ValidationSchemaCache
class that manages our schemasschemaCache
Map stores the base schema definitionsgetSchema
method always returns a clone of the cached schema using clone()
validate
method provides a convenient way to validate data using a cached schemaSome of the pros of using this approach:
You may expand this further by: