简体   繁体   中英

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.

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.

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
});

Joi 17.4 上validate()返回的error有一个名为details的属性,您可以从中访问有关这些错误的详细信息(例如这些错误属于哪些字段)。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM