24

JSON Schema enums

JSON Schemas feature enums, which impose a constraint on the values of a string type:

{
    "type": "array",
    "items": [
        {
            "type": "number"
        },
        {
            "type": "string"
        },
        {
            "type": "string",
            "enum": ["Street", "Avenue", "Boulevard"]
        },
        {
            "type": "string",
            "enum": ["NW", "NE", "SW", "SE"]
        }
    ]
}

This schema validates values such as [1600, "Pennsylvania", "Avenue", "NW"].

The problem

Is there an elegant way to make the enum case-insensitive, so that both Avenue and avenue would be accepted as the third value in the array?

Other possible solutions

I can use anyOf on a list of values, and validate each against a case-insensitive regex - but that's cumbersome, error-prone and inelegant.

Adam Matan
  • 128,757
  • 147
  • 397
  • 562

4 Answers4

9

I'm afraid you won't find any elegant solution to this. There was a proposal for case-insensitive enums and several issues were commented.

So if you can not avoid the requirement, regex solutions are the only feasible ones. Another brute-force approach would be to have n complete lists of enum values, one with starting capital letters, other all capital letters, etc. and then use anyOf as you stated. You can automate the creation of this json-schema easily. Obviously it won't be very readable.

Anyway I would try to solve this with a pre-processing step before validation. You might convert to lowercase the required properties if they are present, and then validate. I find a bit forced to use json-schema specification to allow 'dirty' data.

jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
2

transform method provided in the Ajv-Keywords can be used to have case-insenstive enums.

AjvKeywords(ajv, 'transform');

{
    "type": "array",
    "items": [
        {
            "type": "string",
            "enum": ["NW", "NE", "SW", "SE"],
            "transform": ["toLowerCase"],
        }
    ]
}
Rishab Jain
  • 269
  • 4
  • 16
1

We can achieve the case insensitive for the below enum using the pattern. However json schema doesn't support /i for regex insensitive. So we can achieve with our own regular expressions pattern without using /i.

Enum :

month: { type: 'string', enum: ['may', 'June', 'July'] },

Regex pattern:

month: { type: 'string',  pattern: '^([Mm][Aa][Yy]|[Jj][Uu][Nn][Ee]|
[Jj][Uu][Ll[Yy])$',},

Above regular expression is for one of the value for May, June, July with case insensitive

Majid Hajibaba
  • 3,105
  • 6
  • 23
  • 55
0

I ended up creating 2 helpers to convert string to case insensitive patterns and convert them back to their lowercase version:

const toCaseInsensitive = (v = "") =>
    v
        .split("")
        .map(l => {
            const lower = l.toLowerCase()
            const upper = l.toUpperCase()
            return lower === upper ? lower : `[${lower}|${upper}]`
        })
        .join("")
const fromCaseInsensitive = (v = "") => v.replace(/\[(.)\|(.)\]/g, "$1")

Usage:

toCaseInsensitive("TeSt") -> "[t|T][e|E][s|S][t|T]"
fromCaseInsensitive("[t|T][e|E][s|S][t|T]") -> "test"

Lino Rabolini
  • 235
  • 2
  • 7