javascriptnode.jshapi.jsjoi

Joi validation error from which field to show error next to it in UI


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.


Solution

  • 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.