Skip to content

JSON Schema ​

Every file in data/ has a JSON Schema (draft-07) in schema/. The schemas are generated from the zod schemas the TypeScript types are inferred from, so the types, the schemas and the data can't drift apart: CI fails when any of the three disagree.

Data fileSchema
data/judicial-areas.jsonjudicial-areas.schema.json
data/arrondissements.jsonarrondissements.schema.json
data/cantons.jsoncantons.schema.json
data/canton-boundaries.jsoncanton-boundaries.schema.json
data/arrondissement-boundaries.jsonarrondissement-boundaries.schema.json
data/municipalities.jsonmunicipalities.schema.json
data/regions.jsonregions.schema.json
data/provinces.jsonprovinces.schema.json
data/courts.jsoncourts.schema.json
data/court-locations.jsoncourt-locations.schema.json
data/prisons.jsonprisons.schema.json
data/houses-of-justice.jsonhouses-of-justice.schema.json
data/postal-codes.jsonpostal-codes.schema.json
data/interest-rates.jsoninterest-rates.schema.json
data/public-holidays.jsonpublic-holidays.schema.json

Each schema's $id is its URL on this site, e.g. https://pieterjanscheir.github.io/belgica/schema/courts.schema.json. They're also in the npm package as belgica/schema/courts.schema.json.

Validating the data ​

python
import json
from urllib.request import urlopen
from jsonschema import validate  # pip install jsonschema

# Pinned to a release, so the data and the schema match
BASE = "https://raw.githubusercontent.com/pieterjanscheir/belgica/v0.6.1/"
courts = json.load(urlopen(f"{BASE}data/courts.json"))
schema = json.load(urlopen(f"{BASE}schema/courts.schema.json"))
validate(courts, schema)
ts
import { Ajv } from 'ajv'
import addFormats from 'ajv-formats'
import courts from 'belgica/data/courts.json' with { type: 'json' }
import schema from 'belgica/schema/courts.schema.json' with { type: 'json' }

const ajv = new Ajv()
addFormats(ajv)
ajv.validate(schema, courts) // true

In TypeScript, the zod schemas do the same without a JSON Schema validator.

You'll mostly want this when you keep a copy of the data (a fork with extra records, a cached download) and want to know it still has the shape the package expects.

Zod schemas ​

belgica/schemas exports the zod schemas the package's types are inferred from: one per record (courtSchema, cantonSchema, …), per id (courtIdSchema, a z.enum of every id) and per data file (dataFileSchemas).

ts
import { courtIdSchema, dataFileSchemas } from 'belgica/schemas'

const courts = dataFileSchemas.courts.parse(json) // throws a ZodError on a record that doesn't fit
courtIdSchema.safeParse(input).success // whether a string is a known court id

Only belgica/schemas loads zod; the datasets import their types alone.

Generating types for other languages ​

Because the schemas are standard, you can generate models instead of writing them by hand: datamodel-code-generator for Python (Pydantic), quicktype for C#, Go, Java, Kotlin, Swift and more.

bash
datamodel-codegen --input courts.schema.json --input-file-type jsonschema --output courts.py

datapackage.json ​

The repository root has a datapackage.json, a Frictionless Data Package descriptor: the standard metadata file for open datasets. It lists each data file with its title, description, schema, official sources, licence, and two fields of our own:

  • lastReviewed: the day the dataset was last checked against its sources;
  • reviewEveryMonths: how often it must be checked again. The freshness check opens an issue when a dataset is overdue.

Code under MIT, data under CC BY 4.0. Reference data, not legal advice: check the official sources.