Motivation: JSON Schema provides a comprehensive vocabulary for property-level constraints, but lacks a vocabulary for relational constraints between properties.
Simple use-cases for interproperty expressions are:
-
ensuring an end date is after a start date
expand schema
{ "type": "object", "properties": { "startDate": { "type": "string", "format": "date", "title": "Start Date" }, "endDate": { "type": "string", "format": "date", "title": "End Date" } }, "interpropertyExpressions": [ { // Equivalent infix expression: // {startDate} < {endDate} "expression": "{startDate} {endDate} <", "type": "postfix", "message": "End date must be after start date.", "properties": ["startDate", "endDate"] } ] }
-
ensuring a confirmation password is the same as a password
expand schema
{ "type": "object", "properties": { "password": { "type": "string", "title": "Password" }, "confirmationPassword": { "type": "string", "title": "Confirm Password" } }, "interpropertyExpressions": [ { // Equivalent infix expression: // {password} = {confirmationPassword} "expression": "{password} {confirmationPassword} =", "type": "postfix", "message": "Confirmation password must match password.", "properties": ["password", "confirmationPassword"] } ] }
This repository features an advanced CAD example where the user inputs values defining the hub and rotor for an electric generator.
To run the demo:
-
Install dependencies (requires Node.js).
npm install
-
Start local HTTP server.
npm start
The demo uses a postfix expression, as it's easy to evaluate using a stack, and avoids the use of eval
which poses security risks.
(
The below GIF demonstrates validating the complex relationship between three related inputs explained by the Diagram.
The user can adjust any of the three inputs when the constraint is violated.
GIF | Diagram |
---|---|
diagram.drawio
may be edited at https://app.diagrams.net/
The interpropertyExpressions
keyword MUST be included alongside the schema of an object.
For example:
{
"type": "object",
"properties": {
// ...
},
"interpropertyExpressions": [
// ...
]
}
interpropertyExpressions
includes an array of InterpropertyExpression
objects whose schema is defined by the following meta-schema:
{
"type": "object",
"title": "InterpropertyExpression object",
"properties": {
"expression": {
"type": "string",
"description": "Relational expression between two or more properties where true means valid."
},
"type": {
"type": "string",
"description": "Type of expression. Implementing libraries may only support one or more types.",
"enum": ["postfix", "infix", "prefix"]
},
"message": {
"type": "string",
"description": "Message to display if expression evaluates to false."
},
"properties": {
"type": "array",
"description": "Array of property names included in expression.",
"items": {
"type": "string",
"description": "Property name with dot notation for nested properties."
}
}
}
}
An expression where operators follow operands meeting the following criteria:
-
Operators and operands are delimited by white-space.
Rationale
Avoids ambiguity in parsing expressions where operands contain potential operators.For example, consider the following expression comparing two dates:
2022-12-25 2022-12-26 <
Then the following expression subtracting two numbers:
2022 12 -
Other examples include timestamps (e.g.
2018-11-13T20:20:39+00:00
) and addition (i.e.+
). -
Operators have a fixed number of operands.
Rationale
If every operator has a fixed number of operands, then parentheses are not needed. -
Operators are one symbol.
Rationale
Avoids a lookahead when parsing potentially ambiguous operators such as
<
(if<=
is also an operator). -
Properties are surround by curly-braces (i.e.
{
and}
) with dot notation for nested properties.
The following table documents supported arithmetic operators.
Operator | Name | Operands |
---|---|---|
+ |
Addition | 2 |
- |
Subtraction | 2 |
* |
Multiplication | 2 |
/ |
Division | 2 |
^ |
Exponentiation | 2 |
% |
Modulo | 2 |
The following table documents supported relational operators.
Operator | Name | Operands |
---|---|---|
< |
Less than | 2 |
≤ |
Less than or equal to | 2 |
> |
Greater than | 2 |
≥ |
Greater than or equal to | 2 |
= |
Equal to | 2 |
≠ |
Not equal to | 2 |
According to "A Catalogue of Inter-parameter Dependencies in RESTful Web APIs", "Arithmetic / Relational" dependencies between parameters are the most recurrent across the APIs examined. Additionally, 17% of the inter-parameter dependencies found are of this type.