I would like to specify a regexp pattern for one field based on the data in another. Is this possible? I've tried switch and $data but not sure how to use them. for example, if data looks like:
{
"contacts":[
{
"mode":"Email",
"contact":"[email protected]"
},
{
"mode":"Phone",
"contact":"111-555-1234"
}
]
}
and schema looks something like:
"$schema":"http://json-schema.org/draft-04/schema#",
"type":"object",
"properties":{
"Contacts":{
"type":"array",
"minItems":1,
"items":{
"type":"object",
"properties":{
"mode":{
"type":"string",
"enum":[
"Email",
"Phone"
]
},
"contact":{
"type":"string",
"pattern":"?????"
}
},
"required":[
"mode",
"contact"
]
}
}
}
}
How can I set the pattern of contact based on data in mode, so that if mode is Email, it validates contact against a regexp for an email format, and if mode is Phone, it validates contact against a regexp for a phone format? I have the regexp for each. I need the logic to choose one or the other.
Schemas are a special, object-based way of defining validations or sanitizations on requests. At the root-level, you specify field paths as keys, and objects as values -- which define the error messages, locations and validations/sanitizations.
The simplest way to check if JSON is valid is to load the JSON into a JObject or JArray and then use the IsValid(JToken, JsonSchema) method with the JSON Schema. To get validation error messages, use the IsValid(JToken, JsonSchema, IList<String> ) or Validate(JToken, JsonSchema, ValidationEventHandler) overloads.
There are several ways to do it
anyOf (pros: draft-04 compatible, cons: error reporting is a bit verbose - you will get errors from both subschemas if none matches):
{
"type": "object",
"properties": {
"Contacts": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{
"properties": {
"mode": {"enum": ["Email"]},
"contact": {
"type": "string",
"format": "email"
}
}
},
{
"properties": {
"mode": {"enum": ["Phone"]},
"contact": {
"type": "string",
"pattern": "phone_pattern"
}
}
}
],
"required": ["mode", "contact"]
}
}
}
}
if/then/else (available in ajv-keywords package, pros: error reporting makes more sense, accepted to be included in draft-07, cons: not standard at the moment):
{
"type": "object",
"properties": {
"Contacts": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"mode": {"type": "string", "enum": ["Email", "Phone"]},
"contact": {"type": "string"}
},
"if": {
"properties": {
"mode": {"enum": ["Email"]}
}
},
"then": {
"properties": {
"contact": {"format": "email"}
}
},
"else": {
"properties": {
"contact": {"pattern": "phone_pattern"}
}
}
"required": ["mode", "contact"]
}
}
}
}
select (available in ajv-keywords package, pros: more concise than if/then/else, particularly if there are more than two possible values, cons: not on the standard track yet, but you can support it :), requires enabling $data reference and Ajv v5.x.x):
{
"type": "object",
"properties": {
"Contacts": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"mode": {"type": "string"},
"contact": {"type": "string"}
},
"select": { "$data": "0/mode" },
"selectCases": {
"Email": {
"properties": {
"contact": {"format": "email"}
}
},
"Phone": {
"properties": {
"contact": {"pattern": "phone_pattern"}
}
}
},
"selectDefault": false,
"required": ["mode", "contact"]
}
}
}
}
I prefer the last option.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With