gbroques / json-schema-interproperty-expressions

JSON Schema extension for arithmetic and relational constraints between properties.

Home Page:https://gbroques.github.io/json-schema-interproperty-expressions/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JSON Schema Interproperty Expressions

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:

  1. Install dependencies (requires Node.js).

    npm install
    
  2. 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.

(⚠️ Edge cases are not tested.)

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
Demo Diagram

diagram.drawio may be edited at https://app.diagrams.net/

interpropertyExpressions keyword

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."
      }
    }
  }
}

Postfix Expression

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

Related Work

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.

Frequency of the dependencies according to the number of occurrences and the number of APIs (out of 40) presenting them.

About

JSON Schema extension for arithmetic and relational constraints between properties.

https://gbroques.github.io/json-schema-interproperty-expressions/


Languages

Language:JavaScript 61.8%Language:HTML 34.5%Language:CSS 3.7%