Composition and formatResult
We learned about formatResult
earlier. That validator wrapper provides an easy way to augment or transform the objectProps
and arrayElements
validation results to match the shape your application needs.
In the following example, formatResult
is used to create a validationErrors
validation result prop. The validationErrors
value is flattened array of all validation errors existing in an object or array graph.
import validate, {arrayElements, formatResult} from 'strickland';
const withValidationErrors = (result) => {
const validationErrors = [];
function addErrorsFromObjectProps(resultObjectProps, parentPath) {
if (resultObjectProps) {
Object.keys(resultObjectProps)
// for each prop, get that prop's result
.map((propName) => ({
...resultObjectProps[propName],
propName
}))
// recursively add errors
.forEach(({propName, ...nestedResult}) => {
const propPath = [...parentPath, propName];
addErrorsFromResult({
...nestedResult,
propPath
});
});
}
}
function addErrorsFromArrayElements(resultArrayElements, parentPath) {
if (resultArrayElements) {
// recursively add errors
resultArrayElements.forEach((nestedResult, arrayElement) => {
const propPath = [...parentPath, arrayElement];
addErrorsFromResult({
...nestedResult,
propPath
});
});
}
}
function addErrorsFromResult(nestedResult) {
if (!nestedResult.isValid) {
const {
objectProps,
arrayElements,
propPath = [],
...errorResult
} = nestedResult;
// omit the `objectProps` and `arrayElements`
// result props but include `propPath`
validationErrors.push({propPath, ...errorResult});
addErrorsFromObjectProps(objectProps, propPath);
addErrorsFromArrayElements(arrayElements, propPath);
}
}
addErrorsFromResult(result);
return {
...result,
validationErrors
};
};
const validateWithErrors = formatResult(withValidationErrors, {
name: required(),
addresses: [required(), minLength(1), arrayElements({
addressType: required(),
street: [required(), {
number: required(),
name: required()
}],
city: [required()],
state: [required(), length(2, 2)],
postal: [required(), length(5, 5)]
})]
});
const data = {
name: 'Marty',
addresses: [
{
addressType: 'Home',
street: {
number: 9303,
name: 'Lyon Drive'
},
city: 'Hill Valley',
state: 'CA'
},
{
addressType: 'Work'
}
]
};
const result = validate(validateWithErrors, data);
expect(result).toMatchObject({
validationErrors: [
expect.objectContaining({
value: expect.objectContaining({
name: 'Marty',
addresses: expect.any(Array)
})
}),
expect.objectContaining({
propPath: ['addresses']
}),
expect.objectContaining({
propPath: ['addresses', 0],
value: expect.objectContaining({
addressType: 'Home'
})
}),
expect.objectContaining({
propPath: ['addresses', 0, 'postal'],
required: true
}),
expect.objectContaining({
propPath: ['addresses', 1],
value: expect.objectContaining({
addressType: 'Work'
})
}),
expect.objectContaining({
propPath: ['addresses', 1, 'street'],
required: true
}),
expect.objectContaining({
propPath: ['addresses', 1, 'city'],
required: true
}),
expect.objectContaining({
propPath: ['addresses', 1, 'state'],
required: true
}),
expect.objectContaining({
propPath: ['addresses', 1, 'postal'],
required: true
})
]
});
/*
// Most result props are omitted for illustration
// of the validationErrors contents
result = {
isValid: false,
// objectProps,
// value,
validationErrors: [
{
value: {
name: 'Marty',
addresses: [/* ... */]
})
},
{
propPath: ['addresses']
},
{
propPath: ['addresses', 0],
value: {
addressType: 'Home'
}
},
{
propPath: ['addresses', 0, 'postal'],
required: true
},
{
propPath: ['addresses', 1],
value: {
addressType: 'Work'
}
},
{
propPath: ['addresses', 1, 'street'],
required: true
},
{
propPath: ['addresses', 1, 'city'],
required: true
},
{
propPath: ['addresses', 1, 'state'],
required: true
},
{
propPath: ['addresses', 1, 'postal'],
required: true
}
]
}
*/
Last updated
Was this helpful?