0.1.5 • Published 2 years ago

@jsonhero/schema-infer v0.1.5

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

JSON Schema Infer

Infers JSON Schemas from example JSON. Powers the schema inference of jsonhero.io

Coverage lines Tests Downloads Install size

Features

  • Written in typescript
  • Inspired by jtd-infer
  • Generates valid 2020-12 JSON schema documents from example data
  • Supports most string formats through json-infer-types
    • Date and times
    • URIs
    • Email Addresses
    • Hostnames
    • IP Addresses
    • uuids
  • Supports snapshotting and restoring inference sessions
  • Handles nullable values and required/optional properties

Usage

Install schema-infer:

npm install --save @jsonhero/schema-infer

To produce a JSON Schema document, pass in the example JSON to inferSchema and call toJSONSchema on the result:

import { inferSchema } from "@jsonhero/schema-infer";

inferSchema({
  id: "abeb8b52-e960-44dc-9e09-57bb00d6b441",
  name: "Eric",
  emailAddress: "eric@jsonhero.io",
  website: "https://github.com/ericallam",
  joined: "2022-01-01",
}).toJSONSchema();

Infers the following JSON schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": { "type": "string", "format": "uuid" },
    "name": { "type": "string" },
    "emailAddress": { "type": "string", "format": "email" },
    "website": { "type": "string", "format": "uri" },
    "joined": { "type": "string", "format": "date" }
  },
  "required": ["id", "name", "emailAddress", "website", "joined"]
}

Inferring an array of objects, with some properties being optional:

inferSchema([
  { rank: 1, name: "Eric", winner: true },
  { rank: 2, name: "Matt" },
]).toJSONSchema();

Produces the following schema:

{
  "items": {
    "properties": {
      "name": {
        "type": "string"
      },
      "rank": {
        "type": "integer"
      },
      "winner": {
        "type": "boolean"
      }
    },
    "required": ["rank", "name"],
    "type": "object"
  },
  "type": "array"
}

You can produce better results by inferring from more than 1 example JSON, like so:

let inference = inferSchema({ name: "Eric" });
inference = inferSchema({ name: "James", age: 87 });

inference.toJSONSchema();

Produces:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer" }
  },
  "required": ["name"]
}

If you need to save the inference session for later use you can use the toSnapshot and restoreSnapshot functions:

let inference = inferSchema({ name: "Eric" });
let snapshot = inference.toSnapshot();

await writeFile("./inference.json", JSON.stringify(snapshot));

// Later:
let snapshot = JSON.parse(await readFile("./inference.json"));
inferSchema({ email: "eric@jsonhero.io" }, restoreSnapshot(snapshot));

This library makes use of anyOf to handle a value that can be multiple conflicting types:

inferSchema([1, "three"]).toJSONSchema();

Will produce

{
  "type": "array",
  "items": {
    "anyOf": [{ "type": "integer" }, { "type": "string" }]
  }
}

Examples

Airtable API

Roadmap

  • Add support for hints for discriminators (tagged unions), value-only schemas, and enums
  • Add support for JSON Typedefs
  • Add "verbose" mode to include $id, examples, etc.