Skip to content
Permalink
Browse files

feat: JoiValidationError.objectName, objectId

Joi error message to include objectId / className
  • Loading branch information...
kirillgroshkov committed Apr 17, 2019
1 parent e3485c9 commit 92aa2efe064eeae1735b7f1386633bd058fb8d39
@@ -59,6 +59,7 @@ Object {
"type": "string.min",
},
],
"joiValidationObjectName": "objName",
}
`;

@@ -75,13 +76,13 @@ exports[`getValidationResult should still convert 1`] = `
exports[`long message string 1`] = `
"[
{
\\"a\\" [1, 10, 100, 1000, 101, 102, 103, 104, 105, 106, 107, 108, 109, 11, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 12, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 13, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 14, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 15, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 16, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 17, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 18, 180, 181, 182, 183, 184, 185, 186,
... 37 KB message truncated
\\"a\\" must be a string @ .0.a
\\"a\\" must be a string @ .1.a
\\"a\\" must be a string @ .2.a
\\"a\\" must be a string @ .3.a
\\"a\\" must be a string @ .4.a
\\"a1\\" [1, 10, 100, 1000, 101, 102, 103, 104, 105, 106, 107, 108, 109, 11, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 12, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 13, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 14, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 15, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 16, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 17, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 18, 180, 181, 182, 183, 184, 185, 186,
... 38 KB message truncated
\\"a1\\" must be a string @ .0.a1
\\"a1\\" must be a string @ .1.a1
\\"a1\\" must be a string @ .2.a1
\\"a1\\" must be a string @ .3.a1
\\"a1\\" must be a string @ .4.a1
... 1000 errors"
`;

@@ -118,3 +119,93 @@ exports[`should fail on invalid values 8`] = `

[1] \\"a1\\" length must be less than or equal to 5 characters long"
`;

exports[`should include id in the error message 1`] = `
"Object.someId
{
\\"id\\": \\"someId\\",
\\"a1\\" [1]: -- missing --
}

[1] \\"a1\\" is required"
`;

exports[`should include id in the error message 2`] = `
Object {
"joiValidationErrorItems": Array [
Object {
"context": Object {
"key": "a1",
"label": "a1",
},
"message": "\\"a1\\" is required",
"path": Array [
"a1",
],
"type": "any.required",
},
],
"joiValidationObjectId": "someId",
"joiValidationObjectName": "Object",
}
`;

exports[`should include id in the error message 3`] = `
"ObjName.someId
{
\\"id\\": \\"someId\\",
\\"a1\\" [1]: -- missing --
}

[1] \\"a1\\" is required"
`;

exports[`should include id in the error message 4`] = `
Object {
"joiValidationErrorItems": Array [
Object {
"context": Object {
"key": "a1",
"label": "a1",
},
"message": "\\"a1\\" is required",
"path": Array [
"a1",
],
"type": "any.required",
},
],
"joiValidationObjectId": "someId",
"joiValidationObjectName": "ObjName",
}
`;

exports[`should include id in the error message 5`] = `
"Obj1.someId
{
\\"id\\": \\"someId\\",
\\"a1\\" [1]: -- missing --
}

[1] \\"a1\\" is required"
`;

exports[`should include id in the error message 6`] = `
Object {
"joiValidationErrorItems": Array [
Object {
"context": Object {
"key": "a1",
"label": "a1",
},
"message": "\\"a1\\" is required",
"path": Array [
"a1",
],
"type": "any.required",
},
],
"joiValidationObjectId": "someId",
"joiValidationObjectName": "Obj1",
}
`;
@@ -13,6 +13,8 @@ import { ValidationErrorItem } from 'joi'
*/
export interface JoiValidationErrorData extends ErrorData {
joiValidationErrorItems: ValidationErrorItem[]
joiValidationObjectName?: string
joiValidationObjectId?: string
}

export class JoiValidationError extends AppError<JoiValidationErrorData> {
@@ -1,9 +1,9 @@
import { arraySchema, objectSchema, stringSchema } from './joi.shared.schemas'
import { JoiValidationError } from './joi.validation.error'
import { getValidationResult, validate, validationErrorToString } from './joi.validation.util'
import { getValidationResult, validate } from './joi.validation.util'

interface Obj1 {
a1: string
class Obj1 {
a1!: string
a2?: string
}

@@ -90,10 +90,6 @@ test('getValidationResult valid', async () => {
expect(vr.error).toBeUndefined()
})

test('validationErrorToString', async () => {
expect(validationErrorToString(undefined as any)).toBeUndefined()
})

test('error should contain errorItems', async () => {
const v = {
a1: ' ff ', // to be converted
@@ -155,15 +151,39 @@ test('array items with invalid props', async () => {
// default values

test('long message string', () => {
const objSchema = arraySchema.items(
objectSchema({
a: stringSchema,
}),
)
const objSchema = arraySchema.items(obj1Schema)

const longObject = Array(1000).fill({ a: 5 })
const longObject = Array(1000).fill({ a1: 5 })

const { error } = getValidationResult(longObject, objSchema)
// console.log(error!.message, error!.message.length)
expect(error!.message).toMatchSnapshot()
})

test('should include id in the error message', () => {
const obj = {
id: 'someId',
}

const obj1 = Object.assign(new Obj1(), {
id: 'someId',
})

// No objectName, with id
let { error } = getValidationResult(obj, obj1Schema)
// console.log(error)
expect(error!.message).toMatchSnapshot()
expect(error!.data).toMatchSnapshot()

// ObjectName, with id
;({ error } = getValidationResult(obj, obj1Schema, 'ObjName'))
// console.log(error)
expect(error!.message).toMatchSnapshot()
expect(error!.data).toMatchSnapshot()

// No objectName, with id, constructor name
;({ error } = getValidationResult(obj1, obj1Schema))
// console.log(error)
expect(error!.message).toMatchSnapshot()
expect(error!.data).toMatchSnapshot()
})
@@ -6,6 +6,7 @@
* "Converts" mean e.g trims all strings from leading/trailing spaces.
*/

import { isObject } from '@naturalcycles/js-lib'
import { SchemaLike, ValidationError, ValidationOptions } from 'joi'
import { Joi } from './joi.extensions'
import { JoiValidationError } from './joi.validation.error'
@@ -49,9 +50,7 @@ export function validate<T> (
})

if (error) {
throw new JoiValidationError(validationErrorToString(error, objectName), {
joiValidationErrorItems: error.details,
})
throw createError(value, error, objectName)
}

return returnValue
@@ -78,18 +77,23 @@ export function getValidationResult<T> (
}

if (error) {
vr.error = new JoiValidationError(validationErrorToString(error, objectName), {
joiValidationErrorItems: error.details,
})
vr.error = createError(value, error, objectName)
}

return vr
}

export function validationErrorToString (err: ValidationError, objectName?: string): string {
function createError (value: any, err: ValidationError, objectName?: string): JoiValidationError {
if (!err) return undefined as any
const tokens: string[] = []
if (objectName) tokens.push(objectName)

const objectId = isObject(value) ? (value['id'] as string) : undefined

if (objectId || objectName) {
objectName = objectName || (value && value.constructor && value.constructor.name)

tokens.push([objectName, objectId].filter(i => i).join('.'))
}

// Strip colors in production (for e.g Sentry reporting)
const stripColors = process.env.NODE_ENV === 'production'
@@ -110,5 +114,11 @@ export function validationErrorToString (err: ValidationError, objectName?: stri
tokens.push(annotation)
}

return tokens.join('\n')
const msg = tokens.join('\n')

return new JoiValidationError(msg, {
joiValidationErrorItems: err.details,
...(objectName && { joiValidationObjectName: objectName }),
...(objectId && { joiValidationObjectId: objectId }),
})
}

0 comments on commit 92aa2ef

Please sign in to comment.
You can’t perform that action at this time.