Joi concat with object nested in array - javascript

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?

Related

Joi nested when validation

I am trying to validate a nested object conditionally based upon a value in the parent.
const schema = Joi.object({
a: Joi.string(),
b: Joi.object({
c: Joi.when(Joi.ref('..a'), { is: 'foo', then: Joi.number().valid(1), otherwise: Joi.number().valid(2) }),
}),
});
const obj = {
a: 'foo',
b: {
c: 2,
},
};
In this example, I want to get an error that c must be 1, but the validation passes. I've tried with and without references, but I clearly must be misunderstanding something fundamental about how Joi works. Any help?
you need one more . in your Joi.ref() call. .. will go up to the parent tree, then another dot to signify the property. So for your case it would go to the parent .. then get the a property parent.a
Using the Joi playground this worked for me:
Joi.object({
a: Joi.string(),
b: Joi.object({
c: Joi.when(Joi.ref('...a'), {
is: 'foo',
then: Joi.number().valid(1),
otherwise: Joi.number().valid(2)
})
})
})
If you don't need Joi.ref, this would still work with ... referencing the parent's sibling, like about14sheep pointed out in their answer. I ended up doing something like this:
Joi.object({
a: Joi.string(),
b: Joi.object({
c: Joi.when('...a', {
is: 'foo',
then: Joi.number().valid(1),
otherwise: Joi.number().valid(2),
}),
}),
});

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

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.'
})
})
})

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

Joi array Object validation based on root key value

I have a complex scenario that I want to validate using Joi
here sample Joi Object Schema
const itemSchema = Joi.object({
product_id: Joi.string().required(),
quantity: Joi.number().required().min(0)
});
let objSchema = {
items: Joi.array().items(itemSchema).required().min(1),
item_return_flag: Joi.string().optional().valid(true, false)
};
depending opon item_return_flag key value true or false, I want to change the items.quantity min value requirement. When true, quantity will be 0 , otherwise it will be 1.
Is there anyway, to control the definition of validation of the object in an array, based on the root object in Joi
The sample code that will switch the schema based one the parent key item_return_flag. Schema of the array need to switch based using Joi.altertnatives()
let itemArr = Joi.object({
product_id: Joi.string().required(),
quantity: Joi.number().required().min(0)
});
let itemArr2 = Joi.object({
product_id: Joi.string().required(),
quantity: Joi.number().required().min(1)
});
let itemSchema = Joi.alternatives()
.when('item_return_flag', { is: true, then: Joi.array().items(itemArr).required().min(1), otherwise: Joi.array().items(itemArr2).required().min(1)}) ;
let objSchema = {
items: itemSchema,
item_return_flag: Joi.string().optional().valid(true, false)
};
It looks to me like you could, following the API docs, do something like this:
let objSchema = {
items: Joi.array().items(Joi.object({
product_id: Joi.string().required(),
quantity: Joi.alternatives().when('item_return_flag', {
is: true, then: Joi.number().required().min(0),
otherwise: Joi.number().required().min(1)
})
})).required().min(1),
item_return_flag: Joi.string().optional().valid(true, false)
};
I'm not 100% sure that's the exact correct structure, but it's close. The Joi.alternatives() is provided for just such use cases.

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(),
// ...)

Categories

Resources