Reputation: 1205
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.
Upvotes: 1
Views: 59
Reputation: 1082
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:
Upvotes: 1