DEV Community

Cover image for JSON-schemas are awesome
Nicky Meuleman
Nicky Meuleman

Posted on • Originally published at nickymeuleman.netlify.com

JSON-schemas are awesome

Configuration files

Did those words make you feel (a bit of) dread?

You are not alone, writing configuration files is pretty low on most developers' list of favorite pastimes.

When writing these files (for example a .eslintrc.json) spelling is one of your greatest enemies.

Was it no-unused-vars, noUnusedVars, no-unused-var or something else?

Many hours of devtime have been lost to spelling

Remembering what a certain key expects to receive as value is another one of those enemies.

Does this expect an array or an object, I don't remember 😰

One will work, the other grants a one way ticket to crypticError town.

For those reasons (and more), having the docs open while you write your configuration is an absolute must

There is a better way

The solution? Laziness

I'm kidding, partly. The solution is a JSON-schema.
Leveraging one of those means you can rely on the intelligent autocompletion and error detection to do the heavy lifting!

To get started with the least amount of effort, you can use VSCode, which has builtin support for JSON-schema. Create a file that is listed at schemastore.org and trigger the autocomplete in the editor (ctrl/cmd + space)

empty .babelrc file

Hitting tab on an option in that list and automatically getting empty straight brackets if that key expects an array as value is so helpful.
Play around with your configuration file of choice. If the schema supports it, the amount of nesting doesn't matter, your editor will know what can fit there.

You can define the exact schema you want to use in your editor's workspace settings.
When I wrote this, I knew you could do that, but not how.
Luckily for me the autocomplete powered by, you guessed it, a JSON-schema, told me exactly what it expected.

in VSCode workspace settings .json file (ctrl/cmd+shift+p to search for it)

{
  "json.schemas": [
    {
      "fileMatch": ["/.babelrc"],
      "url": "http://json.schemastore.org/babelrc"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Your own schema

A schema doesn't need to be remote. You can also link your file of choice to a self written and/or local schema.

In this json file, we point to the schema used to validate against.

Many (but not all) editors support this way of linking a file to a schema

in drivers.json

{
  "$schema": "./drivers.schema.json"
}
Enter fullscreen mode Exit fullscreen mode

The $schema value points to a schema file in the same directory

in drivers.schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema"
}
Enter fullscreen mode Exit fullscreen mode

The $schema value here defines which version of the JSON-schema spec is being used.

A bare-bones file is boring, the code beneath adds a few contraints to driver.json

in drivers.schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "title": "Drivers",
  "description": "Formula 1 drivers",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string"
    },
    "series": {
      "type": "string"
    },
    "season": {
      "type": "integer"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Title and description are meant to describe the file that follows this schema.
  • The entire file should be of the type object (which isn't a problem, since it's json)
  • Only the (top-level) properties/keys we declare are accepted.
  • Each one of those properties should be of the specified type.

Here I tried to define the season as "2018"

incorrect type error

Now: something more complex.

in drivers.schema.json

{
  // ...
  "properties": {
    // ...
    "driverList": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/driver"
      }
    }
  },
  "definitions": {
    "driver": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "raceNumber": {
          "type": "integer",
          "minimum": 0,
          "maximum": 99,
          "description": "number this driver races with"
        },
        "code": {
          "type": "string",
          "minLength": 3,
          "maxLength": 3,
          "description": "3 letter abbreviation"
        },
        // ...,
        "team": {
          "$ref": "#/definitions/team"
        }
        // ...
      },
      "required": ["raceNumber", "code", "team"]
    },
    "team": {
      "enum": [
        // ...
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The entire file is available in this gist

This is an example of a file that would satisfy that schema

in drivers.json

{
  "$schema": "./drivers.schema.json",
  "series": "f1",
  "season": 2018,
  "driverList": [
    {
      "raceNumber": 14,
      "code": "ALO",
      "firstName": "Fernando",
      "lastName": "Alonso",
      "dateOfBirth": "1981-07-29",
      "team": "MCLAREN",
      "quotes": ["GP2 engine, GP2", "5 second penalty? Issa yoke"]
    },
    {
      "raceNumber": 3,
      "code": "RIC",
      "firstName": "Daniel",
      "lastName": "Ricciardo",
      "dateOfBirth": "1989-07-01",
      "nationality": "Australian",
      "team": "REDBULL"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

All information can be found in the official specification docs.

The various options you can provide are listed in their schema validation document specifically.

That's a tough read.
No need to worry if that isn't your cup of tea, because JSON-schema has that intelligent autocompletion and error handling itself!
The information you get in your editor while working on a schema-file is excellent.

autocomplete while writing a schema

The understanding JSON schema is also an excellent way to get the information you're looking for. It's based on version 6 of the spec currently and will get an update soon!

Not just JSON

These JSON-schemas can also apply to other filetypes, like YML

Install the YML support extension by Red Hat.

Linking a remote schema to a file can be done in your workspace settings.

{
  "yaml.schemas": {
    "http://json.schemastore.org/prisma": "prisma.yml"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now my prisma.yml file is ready to go!

prisma.yml with working schema

The top level "type": "object" we had in our drivers.schema.json can be another value now.
For example "array" for a drivers.yml that contains one big top level list.

Top comments (0)