sagold / json-schema-library

Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation
MIT License
164 stars 19 forks source link

Unable to get default values for all properties #21

Closed oscarmartingonzalez closed 1 year ago

oscarmartingonzalez commented 1 year ago

I would like to start this thread mentioning that I really like this tool.

I'm trying to design a JSON Schema which default values help to complete the initial data. This is my schema.json file:

{
  "$schema": "http://json-schema.org/draft/2019-09/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["job-type-a", "job-type-b"],
  "properties": {
    "job-type-a": {
      "$ref": "#/definitions/job-type-a"
    },
    "job-type-b": {
      "$ref": "#/definitions/job-type-b"
    }
  },
  "definitions": {
    "cluster": {
      "type": "string",
      "enum": ["cluster-a", "cluster-b"],
      "default": "cluster-a"
    },
    "runner": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "cluster": {
          "$ref": "#/definitions/cluster"
        }
      },
      "required": ["cluster"]
    },
    "job-type-a": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "runner": {
          "$ref": "#/definitions/runner"
        }
      }
    },
    "job-type-b": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "runner": {
          "$ref": "#/definitions/runner"
        }
      }
    }
  }
}

I write this code to get default values for previous schema

import { Draft, Draft07 } from 'json-schema-library';
import jsonSchemaSpec from '../schema.json';

const initData = {};
const jsonSchema: Draft = new Draft07(jsonSchemaSpec);
const data = jsonSchema.getTemplate(initData);
console.log(data);

but the result of the previous code is not the expected. This is the result: { 'job-type-a': { runner: { cluster: 'cluster-a' } }, 'job-type-b': { runner: undefined } }

but I expected a result like that: { 'job-type-a': { runner: { cluster: 'cluster-a' } }, 'job-type-b': { runner: { cluster: 'cluster-a' } } }

I think it is a bug.

sagold commented 1 year ago

Hi there.

Can you try the following before executing getTemplate

import { settings } from "json-schema-library";

settings.GET_TEMPLATE_RECURSION_LIMIT = 2;

Problem is, ref-resolutions can be circular and we need a breaker here. The default is set to 1, but in your case you want refs to be followed twice. Unfortunately this is not yet mentioned in the README.

I hope this helps. Cheers

oscarmartingonzalez commented 1 year ago

Hi @sagold ,

it works 👏👏👏👏👏👏👏, but I have a second use case which is not working fine. Let me show it:

schema.json

{
  "$schema": "http://json-schema.org/draft/2019-09/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["jobs"],
  "properties": {
    "jobs": {
      "$ref": "#/definitions/jobs"
    }
  },
  "definitions": {
    "cluster": {
      "type": "string",
      "enum": ["cluster-a", "cluster-b"],
      "default": "cluster-a"
    },
    "runner": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "cluster": {
          "$ref": "#/definitions/cluster"
        }
      },
      "required": ["cluster"]
    },
    "job": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string"
        },
        "runner": {
          "$ref": "#/definitions/runner"
        }
      },
      "required": ["name", "runner"]
    },
    "jobs": {
      "type": "array",
      "items": [
        {
          "$ref": "#/definitions/job"
        }
      ]
    }
  }
}

example.ts


import { Draft, Draft07, settings } from 'json-schema-library';
import jsonSchemaSpec from './schema.json';

settings.GET_TEMPLATE_RECURSION_LIMIT = 10;
const initData = {
    jobs: [
        { name: "job-1" },
        { name: "job-2" },
    ]
};
const jsonSchema: Draft = new Draft07(jsonSchemaSpec);
const data = jsonSchema.getTemplate(initData);
console.log(data);

The result is { jobs: [ { name: 'job-1' }, { name: 'job-2' } ] }

but I expected a result like that { jobs: [ { name: 'job-1', runner: { cluster: 'cluster-a' } }, { name: 'job-2', runner: { cluster: 'cluster-a' } } ] }

sagold commented 1 year ago

Hi Oscar.

The json-schema does not match the expected result The items-definition in you json-schema has to be an object, not an array containing the reference. See the diff here https://github.com/sagold/json-schema-library/commit/b9f4ea33734336f218b4a9e507a850b27fe06aaf.

"jobs": {
  "type": "array",
  "items": 
--  [
    {
      "$ref": "#/definitions/job"
    }
--  ]
}

With this, your data is returned as expected.