skip to Main Content

Imagine a user writing some config files with some of the properties accepting either a plain value or an array of values of the same type.

The use case is convenience and readability from a user perspective where you don’t want to clutter the file with unnecessary array declaration when a single item is needed.

Here is simple example of what I mean:

{
  // valid
  "accepted_values": 1,

  // valid
  "accepted_values": [1, 2, 3],

  // invalid
  "accepted_values": null

  // invalid
  "accepted_values": []
}

And associated schema:

{
  "properties":{
    "accepted_values": {
      "oneOf": [
        { "type": "number" },
        {
          "type": "array",
          "items": { "type": "number" },
          "minItems": 1
        }
      ]
    }
  }
}

This same pattern repeats for quite a number a properties, all with different validations of the associated value and I’d like to avoid to create that oneOf trick every time.

Is there a way to structure the schema so I can reference that pattern with something similar to this:

{
  "properties":{
    "accepted_values": {
      "$ref": "#/one_or_more",
      "type": "number",
      // Or any other item definition, could be a complex object here
    }
}

2

Answers


  1. I am afraid you have to do the oneOf trick each time for all different types you need. You can assign the defined patterns to each property using $ref according to the type the property has to be.

    There is no thing like a "template" to set the type.

    Edit: You can avoid the oneOf as shown in the answer of Jason from above. The approach is still the same.

    Login or Signup to reply.
  2. There is a way to create a generic type with dynamic references, but it turns out to be more complicated and verbose than probably make sense for this case.

    There’s an alternative way to express this schema that is less verbose because it drops the oneOf.

    {
      "type": ["number", "array"],
      "items": { "type": "number" },
      "minItems": 1
    }
    

    This works because the items and minItems keywords only apply if the instance is an array. There’s still some duplication, but it’s as concise as it’s going to get.

    If you’re using these multiple times, you can use definitions to reduce the boilerplate a bit more.

    {
      "type": "object",
      "properties": {
        "aaa": { "$ref": "#/$defs/number-or-array" },
        "bbb": { "$ref": "#/$defs/number-or-array" },
        "ccc": { "$ref": "#/$defs/string-or-array" },
        ...
      },
    
      "$defs": {
        "number-or-array": {
          "type": ["number", "array"],
          "items": { "type": "number" },
          "minItems": 1
        },
        "string-or-array": {
          ...
        },
        ...
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search