'Joi validations - if this and that, then. Else
I'm trying to apply multiple validations to a Joi schema that checks the value of two keys and validates a final key based on the result.
Using the example body of below, I want to check the field of channel. This could be either LOCAL or GLOBAL.
{
"channel":"LOCAL",
"beneficiary": {
"currency": "GBP",
"accountNumber": "12345678"
}
}
If LOCAL and the beneficiary.currency is GBP, then the following should apply: Joi.string().regex(/^[0-9]{8}$/).required()
If GLOBAL and the beneficiary.currency is also GBP, then the following should apply: Joi.string().regex(/^[A-Z]{2}[0-9]{2}([0-9]|[A-Z])+([0-9A-Z]+){10,31}$/).required()
However this needs to work for a matrix of many possibilities as per the following +n amount of supported currencies.
| TYPE | CURRENCY | REGEX |
|---|---|---|
| GLOBAL | USD | ^[A-Z]{2}[0-9]{2}([0-9]|[A-Z])+([0-9A-Z]+){10,31}$ |
| LOCAL | USD | ^[0-9A-Z]{1,45}$ |
| GLOBAL | GBP | ^[A-Z]{2}[0-9]{2}([0-9]|[A-Z])+([0-9A-Z]+){10,31}$ |
| LOCAL | GBP | ^[0-9]{8}$ |
| GLOBAL | AUD | ^[A-Za-z0-9]{0,9}$ |
| LOCAL | AUD | ^[0-9]{1,7}$ |
| GLOBAL | SGD | ^[A-Za-z0-9]+$ |
| LOCAL | SGD | ^[A-Za-z0-9]{1,50}$ |
I've found I can use the following but doesn't scale across the matrix of possible options:
accountNumber: Joi.string().when(Joi.ref('...channel', {
is: 'LOCAL',
then: Joi.when(Joi.ref('currency'), { is: 'GBP', then: Joi.string().regex(/^[0-9]{8}$/).required() })
})
Solution 1:[1]
I would use oneOf for this use case:
{
"type": "object",
"$schema": "http://json-schema.org/draft-06/schema#",
"description": "JSON schema generated with JSONBuddy https://www.json-buddy.com",
"oneOf": [
{
"properties": {
"channel": {
"type": "string",
"const": "GLOBAL"
},
"beneficiary": {
"$ref": "#/definitions/beneficiary-GLOBAL-USD"
}
}
},
{
"properties": {
"channel": {
"type": "string",
"const": "LOCAL"
},
"beneficiary": {
"$ref": "#/definitions/beneficiary-LOCAL-USD"
}
}
}
],
"definitions": {
"beneficiary-GLOBAL-USD": {
"type": "object",
"properties": {
"accountNumber": {
"pattern": "^[A-Z]{2}[0-9]{2}([0-9]|[A-Z])+([0-9A-Z]+){10,31}$"
},
"currency": {
"const": "USD"
}
}
},
"beneficiary-LOCAL-USD": {
"type": "object",
"properties": {
"accountNumber": {
"pattern": "^[0-9A-Z]{1,45}$"
},
"currency": {
"const": "USD"
}
}
}
}
}
If you also put the single sub-schemas as $ref in separate definitions is up to you. But I am afraid you can't get much less verbose.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Clemens |
