Advanced validation rules let you react to contextual data, enforce dependencies between properties, and design predictable nested schemas.
Conditional rules
Use the when clause to activate a rule only if a condition evaluates to true. The condition uses the same operators as the search DSL on the profile’s property paths.
{
"properties": {
"practiceNumber": { "type": "integer" },
"specialties": {
"type": "array",
"rules": [
{
"required": true,
"min": 1,
"when": {
"eq": {
"practiceNumber": "*"
}
}
}
],
"items": { "type": "symbol" }
}
}
}
Supported operators
| Operator | Description |
eq | Checks equality. Use * as a wildcard to test for presence. |
lt | Valid for numeric or temporal fields to enforce “less than or equal.” |
gt | Valid for numeric or temporal fields to enforce “greater than or equal.” |
Combine multiple rules in the same array to express complex validation logic.
Nested objects
when clauses reference properties from the root of the profile. For nested structures, use dot notation:
{
"properties": {
"details": {
"type": "object",
"properties": {
"contact": {
"type": "contactpoint",
"properties": {
"system": {
"rules": [
{
"required": true,
"enum": ["phone", "fax", "email"]
}
]
}
}
},
"emailCC": {
"type": "symbol",
"rules": [
{
"required": true,
"when": {
"eq": {
"details.contact.system": "email"
}
}
}
]
}
}
}
}
}
Arrays of objects
Similar to the above, when using an operator on a property that is inside of an array, two choices are possible:
- If you want to test if at least one object/property of the array follows the clause, refer directly to the property (Inside or outside the array).
- If you want to test against another property in the same object (Property with the rule must also be in the same object), you can use the
[current] clause.
This could result in profile definitions such as:
Testing for the condition: “emailCC is required if ANY contact point system is of type "email"”:
{
"properties": {
"contacts": {
"type": "array",
"items": {
"type": "contactpoint"
}
},
"emailCC": {
"type": "symbol",
"rules": [
{
"required": true,
"when": {
"eq": {
// Referring to any items in "contacts"
"contacts.system": "email"
}
}
}
]
},
"aRootProperty": {
"type": "symbol"
}
}
}
Creating the following resource is valid: since no contact point has a system of type “email”, emailCC is not required.
{
"contacts": [{ "system": "phone" }]
}
Creating the following resource is not valid: since one contact point has a system of type “email”, emailCC is required.
{
"contacts": [{ "system": "email" }, { "system": "phone" }]
}
Testing for the condition: “value must be defined if the contact system value is of type "email"”.
{
"properties": {
"contacts": {
"type": "array",
"items": {
"type": "contactpoint",
"properties": {
"value": {
"rules": [
{
"required": true,
"when": {
"eq": {
// Referring to the current item in "contacts"
"contacts[current].system": "email"
}
}
}
]
}
}
}
}
}
}
Cardinality
Cardinality expresses how many instances of a property are allowed within a complex type.
| Notation | Name | Description | Validation |
0:1 | Zero to one | Optional property, maximum one value | Property can be omitted or appear once |
1:1 | One to one | Required property, exactly one value | Missing or duplicate values fail validation |
0:* | Zero to many | Optional property, unlimited values (arrays) | Property can be omitted or contain any number of elements |
1:* | One to many | Required property, at least one value (arrays) | Enforces a non-empty array |
{
"patientName": {
"family": "Wilson", // 0:1
"given": ["Sarah", "Elizabeth"], // 0:*
"use": "official" // 0:1
}
}
Cardinality rules are enforced during validation. Missing required properties or over-populated single-valued properties will fail ingestion.
Continue with vocabulary binding to link fields to controlled concept sets.