How can I have multiple unique checks with a Joi schema validation? - javascript

I have data:
const mockScenario1 = {
drawingNode: {
moduleRackOutputs: [
{
moduleId: 'module1',
tilt: 'tilt1',
rack: {
framingType: 'framing1'
}
},
{
moduleId: 'module2',
tilt: 'tilt1',
rack: {
framingType: 'framing1'
}
}
]
}
}
I want to ensure that:
If there are different moduleId values, I want: Only one module allowed
If there are different rack.framingType values, I want: Only one framing type allowed
I have this sort of started with:
Joi.object({
drawingNode: Joi.object({
moduleRackOutputs: Joi.array()
.items(
Joi.object().keys({
moduleId: Joi.string().required(),
tilt: Joi.string().required(),
rack: Joi.object({
framingType: Joi.string().required()
})
})
)
.unique((a, b) => a.moduleId !== b.moduleId)
.messages({
'array.unique':
'The drawing contains more than one module type. Multiple module types are not yet supported by the PVsyst RPA.'
})
})
})
Which works for the module, but not the framingType. Seems I can't use multiple unique?
I'd love any help or pointers. Thanks!

Here is the Solution. I hope it would help.
Joi.object({
drawingNode: Joi.object({
moduleRackOutputs:
Joi.array().unique('moduleId').unique('rack.framingType')
.messages({
'array.unique':
'The drawing contains more than one module type. Multiple module types are not yet supported by the PVsyst RPA.'
})
})
})
OR
Joi.object({
drawingNode: Joi.object({
moduleRackOutputs: Joi.array()
.items(
Joi.object().keys({
moduleId: Joi.string().required(),
tilt: Joi.string().required(),
rack: Joi.object({
framingType: Joi.string().required()
})
})
)
.unique((a, b) => a.moduleId === b.moduleId || a.rack.framingType === b.rack.framingType)
.messages({
'array.unique':
'The drawing contains more than one module type. Multiple module types are not yet supported by the PVsyst RPA.'
})
})
})

Related

Add error in existing errors while validating object through hapi/joi

const schema = Joi.object().keys({
Id: Joi.number().required(),
CustomerName: Joi.string()
.trim()
.required()
.when('$isInValidCustomer', {
is: true,
then: //Add some error in existing error block,
}),
BankName: Joi.string().trim(),
});
const custDetail = {
Id: 2,
CustomerName: 'xyz'
BankName: ''
};
const schemaOptions = {
abortEarly: false,
context: {
isInValidCustomer: true,
},
};
const valError = schema.validate(custDetail, schemaOptions);
So, now when I validate 'custDetail' object I want following 2 errors:
- CustomerName error because 'isInValidCustomer' is true
- BankName is required
I am not able to append error for CustomerName in existing error object. If I use '.error()' then just get single error corresponding to 'CustomerName' else just getting error for BankName.
Any help is really appreciated.
This can be achieved using custom function.
const schema = Joi.object().keys({
Id: Joi.number().required(),
CustomerName: Joi.string()
.trim()
.required()
.when('$isInValidCustomer', {
is: true,
then: Joi.any().custom(() => {
throw new Error('Invalid Customer');
}),
}),
BankName: Joi.string().trim(),
});

Complex validation using Joi library

I have this json:
let purchaseSubscription = {
'metadata': {
'eventName': 'PurchaseSubscription',
'type': 'setup' // setup, repurchase or recurring
},
'data': {
'subscriptionId': '447481',
'subscriptionTrialId': '23542'
}
};
If the metadata.type has value setup
then data.subscriptionTrialId should be validated for existence and to be a number.
If the metadata.type has other values, the data.subscriptionTrialId can be ignored.
This is what I currently have:
const Joi = require('joi');
const validTypes = ['setup', 'repurchase', 'recurring'];
exports.schema = Joi.object().keys({
metadata: Joi.object({
eventName: Joi.string().required(),
type: Joi.string().valid(validTypes).required()
}).required(),
data: Joi.object({
subscriptionId: Joi.number().integer().min(1).max(2147483647).required(),
subscriptionTrialId: Joi.when(
'metadata.type', { is: 'setup', then: Joi.required() })
}).required()
}).options({ 'allowUnknown': true });
But I am not getting desired results. The data.subscriptionTrialId is always validated, no matter what I have under metadata.type
I tried reading documentation, but can't make it to work :(
You can use the otherwise key in the JOI schema.
Somewhere in your code before declaring exports.schema:
const trialIdRequired = Joi.object({
subscriptionId: Joi.number().integer().min(1).max(2147483647).required(),
subscriptionTrialId: Joi.required()
}).required()
const trialIdNotRequired = Joi.object({
subscriptionId: Joi.number().integer().min(1).max(2147483647).required(),
subscriptionTrialId: Joi.any()
})
And then add a when clause to the data field
data: Joi.when(
'metadata.type',
{
is: 'setup',
then: trialIdRequired,
otherwise: trialIdNotRequired
})

Array of objects with different schemas - JOI

I currently have the following schema on my app:
Joi.object().keys({
users: Joi.array().items(mySchema)
})
So I can get an array of users and validate them.
But now I need different schemas for each object.
Is there a way I can do something like:
Joi.object().keys({
users: [
Joi.object().keys(mySchemaForUserOne),
Joi.object().keys(mySchemaForUserTwo),
// ...
]
})
Here you go ~
Joi.object().keys({
users: Joi.array().items(
Joi.alternatives()
.conditional('.type', {
switch: [{
is: 'mySchemaForUserOne',
then: Joi.object({ ... }),
}, {
is: 'mySchemaForUserTwo',
then: Joi.object({ ... }),
}],
})
)
})
You can check documents here =>
Joi conditional API
You can use array.items by listing all allowed types. If a given type is .required() then there must be a matching item in the array: joi API reference
users: Joi.array().items(Joi.object().keys(mySchemaForUserOne).required(),
Joi.object().keys(mySchemaForUserTwo).required(),
// ...)

Making one input as required based on the input of another key

I am using JOI for schema validation. In the following schema, I want input_file to be of type required when type is jobType.MBR, otherwise file_name must remain of type required
const jobObjectSchema = {
type: Joi.string().valid(jobType.MBR, jobType.MP4).required(),
file_name: Joi.string().required(),
input_file: Joi.string()
};
How can I do this?
Use Joi any().when.
const jobObjectSchema = {
type: Joi.string().valid(jobType.MBR, jobType.MP4).required(),
file_name: Joi.any().when('type', {
is: jobType.MBR,
then: Joi.string().optional(),
otherwise: Joi.string().required()
}),
input_file: Joi.any().when('type', {
is: jobType.MBR,
then: Joi.string().required(),
otherwise: Joi.string().optional()
})
};

Joi concat with object nested in array

I currently have this Joi scheme:
scheme1 = Joi.object({
arr: Joi.array.items(Joi.object().keys({
value: Joi.number()
}))
})
And another one (that I can't edit/read) which looks the same with different object keys
scheme2 = Joi.object({
arr: Joi.array.items(Joi.object({
otherValue: Joi.number(),
moreValues: Joi.string()
}))
})
I now need to merge these in such a way that I get something like this:
result = Joi.object({
arr: Joi.array.items(Joi.object({
value: Joi.number(),
otherValue: Joi.number(),
moreValues: Joi.string()
}))
})
By using scheme1.concat(scheme2) I only get:
Joi.array.items(object1, object2)
How can I do this, without modifying or accessing (apart from concat) the second scheme?

Categories

Resources