import Joi from 'joi'; import { IError } from '../interfaces/common'; export type JoiValidatorResponse = { value: T; errors: Joi.ValidationErrorItem[]; } const encodeError = (message: string, error: Joi.ErrorReport): Joi.ErrorReport => { error.message = message; return error; }; const hasErrors = (errors: Joi.ValidationErrorItem[]) => errors.length > 0; const validate = (schema: Joi.ObjectSchema, params: any): JoiValidatorResponse => { const validator = schema.validate(params); const { value, error } = validator; /** * If phone number input with no numbers, return 'Required' instead of 'Invalid' for consistency. * This is because react-phone-input-2 always has a "+" in value and thus Joi assesses it as Invalid * as opposed to empty. */ const phoneError = error?.details.find((error) => error.path.includes('phoneNumber')); if (phoneError) { phoneError.message = 'Required'; } return { value, errors: error?.details ?? [], }; }; const errorsToMessage = (errors: Joi.ValidationErrorItem[]): string => errors.map((error) => error.message).join('\n'); const joiErrorPathToJsonPointer = (path: (string | number)[]) => `/${path.map((v) => v.toString()).join('/')}`; const parseErrors = (errors: Joi.ValidationErrorItem[]): Record => { const parsedErrors = errors.reduce((cur: Record, error: Joi.ValidationErrorItem) => { cur[joiErrorPathToJsonPointer(error.path)] = error.message; return cur; }, {}); return parsedErrors; }; const createResponseError = (errors: Joi.ValidationErrorItem[]): Required => ({ message: errorsToMessage(errors), fields: parseErrors(errors), }); const JoiUtil = { validate, encodeError, hasErrors, errorsToMessage, parseErrors, createResponseError, }; export default JoiUtil;