0

I want to load (require) a folder with json schemas that have references based on their file.

In other words I have

Schema1: 
{ //Schema stuff ....
    "$ref": "./json_schema2_file.json#someElement"
}

And in another file in the same folder:

Schema2
{//Schema stuff...
"$id": "/someElement"
}

These Schemas are in sperate files and now should be loaded into JS to be validated against a json object. However, the references inside the folder should still be valid.

That's why my question was, if and how it is possible to load a folder full of json files without references to break.

Those schemas will be used to validate json objects by this library: https://github.com/tdegrunt/jsonschema I'm personally using Node with Angular so using fs would only work for node, but would be a start.

8
  • Your references are not quite correct. I can't form a full answer right now, but take a look at the library documentation on how to do this at github.com/tdegrunt/… Commented Jul 2, 2019 at 12:23
  • Do you mean reference in the library of tdgrunt or references of json schema in general? Because I created a folder full of json schemas where the reference should be correct but the library of tdgrunt has a different way of referencing if I saw that correctly. Commented Jul 2, 2019 at 12:25
  • You've written your JSON Schema references incorrectly for the given $ids. JSON Schema itself has no idea about individual files or a file system as such, but uses URI resolution protocols. Imagine your $ref is an HTML link href, which only knows about the current URL of the page it is on. Does that help? Commented Jul 2, 2019 at 12:28
  • I followed this: swagger.io/docs/specification/using-ref maybe I have to put another dot though. Webstorm found it though, so I assumed it was correct. I tested it with ./ ../ and without / Commented Jul 2, 2019 at 12:31
  • Ugh this explains why we see so many issues. Relative locations only works for remote references automagically if $id reflects the URL it's accessible on, and all schemas are provided at said URLs and relative paths, AND the library you use supports (usually with a flag) remote http resolution. Commented Jul 2, 2019 at 12:34

3 Answers 3

1

In your Node backend, require can be used to import JSON files as if it was a normal JavaScript file:

// data.json
{ "hello": "world" }

// main.js
const data = require('./data.json');
console.log(data); // { hello: 'world' }

For your Angular frontend, it depends on how you build your bundle, but normally using import data from './data.json' should yield the same result (as said in this question).


Now comes the question: what can you do if your schemas are in multiple JSON files?

Natively neither require nor import take the time to resolve the $ref and $id properties and to bundle everything into a single JS object. There doesn't seem to be any simple native way to parse everything, luckily the NPM package json-schema-ref-parser does exactly that! It could be used as such in your use case:

// foo.schema.json 
{
    "type": "object",
    "properties": {
        "bar": {
            "$ref": "./bar.schema.json"
        }
    }
}

// bar.schema.json 
{
    "type": "number"
}

// main.js 
const parser = require('json-schema-ref-parser');
parser.dereference('foo.schema.json', (err, schema) => console.log(schema));
// logs: { type: 'object', properties: { bar: { type: 'number' } } }
Sign up to request clarification or add additional context in comments.

4 Comments

This loads a single json file. However in this json (schema) there are references that assume their folder as the root folder. If I require the json file as suggested the first ref throws an error.
SchemaError: no such schema </meta_nlp_schema.json#meta> to be precise. meta is refed like this: "$ref": "./meta_nlp_schema.json#meta", and the id is: "$id": "/meta", which means that the reference is broken or I did it wrong^^.
Done! I edited my answer with the use case handling you required. Is that ok now?
It should work. However I still got into an Issue with that library described here: github.com/APIDevTools/json-schema-ref-parser/issues/130 But if that can be resolved I think that it should do the trick. In other words your answer should be the answer to my question. Thank you.
0

Typically, JSON Schema parsers (including the jsonschema package, which I maintain) don't automatically load references resusively. You just need to provide the additional files that have the schemas:

var Validator = require('jsonschema').Validator;
var v = new Validator();
v.addSchema(require('./json_schema.json'), 'http://example.com/json_schema.json');
v.addSchema(require('./json_schema2.json'), 'http://example.com/json_schema2.json');

Don't forget to give your schemas a full URI, otherwise they might not work consistently between applications.

If you want to automatically import references, the jsonschema package provides a list of the known schemas without definitions in the Validator#unresolvedRefs property. Shift off this stack and import the reference with Validator#addSchema:

async function importUnresolved(){
    for(var uri; uri = v.unresolvedRefs.shift();){
        // where `get` is some resolver that downloads the schema
        schema = await get(uri);
        if(!schema) throw new Error(`Could not dereference JSON schema: <${uri}>`);
        v.addSchema(schema, uri);
    }
}

1 Comment

Does that work with ref to specific elements? I'm confident that you can get the json file of that schema, does it still resolve if I ref a definition in a Schema? Something like ./folder/schema.json#myElement ? the get function will have to slice the #myElement part of to get the file and readd it but is v.addSchema(schema, ./folder/schema.json#Element) to resolve elements in definitions (other kind of nested stuff)? I'm Sorry but I really get confused with all the different types of uris in different contexts and what they are able to do and what not.
-1

1.Write json content with the use of json parser to avoid typos.

 {
     "quiz": 
     [
         {
             "question": "Question 1",
             "a": "Answer a",
             "b": "Answer b",
             "c": "Answer c",
             "correct": "a"
         },
         {
             "question": "Question 2",
             "a": "Answer a",
             "b": "Answer b",
             "c": "Answer c",
             "correct": "b"
         },
         {
             "question": "Question 3",
             "a": "Answer a",
             "b": "Answer b",
             "c": "Answer c",
             "correct": "c"
         }
     ]
 }

2.Save json in the same folder as your js script. I named my file questions.json. 3.Load the json data with $.getJSON. Following example is complete script that loads the questions from json to allQuestions array.

var allQuestions = new Array();
    
function loadQuestions() {
    $.getJSON('question.json', function (data) {
        allQuestions = data.quiz;
    }).error(function(){
            console.log('error: json not loaded');
        });
    });
}

4.Now your json data is available in allQuestions array and you can access it, for example:

var currentQuestion = allQuestions[0].question;
var answerA         = allQuestions[0].a; 

Using .done callback Remember that$getJSON runs asynchronously. Such implementation will be not the best idea:

loadQuestions();
printQuestion(allQuestions[0]); 

It’s possible that by the moment of calling printQuestion the JSON will not be loaded yet and the allQuestions size will be 0. To ensure that some operations are done after the JSON is fully loaded, use .done callback.

var allQuestions = new Array();
    
function loadQuestions() {
    $.getJSON('question.json', function (data) {
        allQuestions = data.quiz;
    })
    .error(function() {
        console.log('error: JSON not loaded'); 
    })
    .done(function() {
        console.log( "JSON loaded!" );
        printQuestion(allQuestions[0]); 
    });
}

2 Comments

That is absurdly way too complicated. Also this implies HTTP requests and everything else that has to be coded in this regard concerning the server and the dev/prod app structure differences. Simply use require/import...
I don't see how this answers the question, which is specific to JSON Schema: json-schema.org

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.