Reputation: 2308
I have to use Joi validation library to validate in the API input and so send the output.
I have say created a schema as follows:
import Joi from '@hapi/joi'
const eventSchema = Joi.object({
title: Joi.string()
.min(7)
.max(50)
.required()
.error(() => Error('Event title has to be least 7 and max 50 characters.')),
description: Joi.string()
.min(10)
.max(400)
.required()
.error(() => Error('Event description has to be least 10 and max 400 characters.')),
place: Joi.string()
.min(6)
.max(40)
.required()
.error(() => Error('Event place has to be least 6 and max 40 characters.'))
})
export default eventSchema
When I validate this, I get validation error as expected. The problem here is I do not know which field really caused error. I wanted to know this because I want exactly to show the error next to that field which caused the error instead of just generic validation message showing at the top of form.
const isValid = eventSchema.validate()
if (isValid.error) {
const fieldNameWhichCauseError = ???
return {
errors: { [fieldNameWhichCauseError]: isValid.error.message }
}
}
// Everything looks good save to db
// ...etc.
The above code has now way to know the field name in fieldNameWhichCauseError = ???. Can somebody please help me? I haven't seen anyone doing such scenario. I also didn't find in the docs. I have so many schemas and validations in place and this is something really blocking me to show the error at proper place in the UI.
Upvotes: 2
Views: 8568
Reputation: 23
import Joi from "joi";
const errorHandler = (err, req, res, next) => {
if (err instanceof Joi.ValidationError) {
// validation error
}
// another error
}
Upvotes: 1
Reputation: 401
On Joi 17.4, the error
returned by validate() has a property called details
, from which you can access the details about those errors (like which fields those errors belong to).
Upvotes: 1
Reputation: 7770
I think there is a better way to achieve this as throwing error is not recommended way to achieve this. (https://github.com/hapijs/joi/blob/master/API.md#anyerrorerr)
You should leverage any.messages
(https://github.com/hapijs/joi/blob/master/API.md#anymessagesmessages) and add your custom messages. The way you are defining them, you always get same type of error message even if user hasn't specified any thing. Also using error overrides abortEarly
options. That means you will not get all the messages, just the first one.
Using messages can be done like this.
const Joi = require('@hapi/joi');
const eventSchema = Joi.object({
title: Joi.string()
.min(7)
.max(50)
.required()
.messages({
'string.base': `"description" should be a type of 'text'`,
'string.min': '"title" has to be least {#limit} characters.',
'string.max': '"title" has to be max {#limit} characters.',
'any.required': `"title" is a required field`,
}),
description: Joi.string()
.min(10)
.max(400)
.required()
.messages({
'string.base': `"description" should be a type of 'text'`,
'string.min': '"description" has to be least {#limit} characters.',
'string.max': '"description" has to be max {#limit} characters.',
'any.required': `"description" is a required field`
}),
place: Joi.string()
.min(6)
.max(40)
.required()
.messages({
'string.base': `"place" should be a type of 'text'`,
'string.min': '"place" has to be least {#limit} characters.',
'string.max': '"place" has to be max {#limit} characters.',
'any.required': `"place" is a required field`
})
});
eventSchema.validate({
"title": "hi"
}, {
"abortEarly": false
});
Upvotes: 1
Reputation: 2308
I figured it out myself. Someday it might help someone searching here.
First I would create a custom ValidationError object.
class ValidationError extends Error {
constructor(message, fieldName) {
super(message)
this.fieldName = fieldName
}
}
Now use this class in the above code posted in Question. Use ValidationError instead of Error class and also pass the field name to it. Example
const eventSchema = Joi.object({
title: Joi.string()
.min(7)
.max(50)
.required()
.error(() => new ValidationError('Event title has to be least 7 and max 50 characters.', 'title'))
})
Remember to use new while using custom class. The code which validates can get error.fieldName
value from the error object passed down.
I hope this is the correct approach. If there is better approach, please post I'll accept it as an answer.
Upvotes: 6