JSON Schema: multiple $ refs are removed when reading a file with a claim
I have a json schema defining multiple properties. I have moved 2 properties into definitions and I am making references to them. I did this because I wanted to bundle them together and do some testing for these properties in general. This works great and all json data is still processed.
But I noticed that when I read the json schema file in the javascript file, I only see the last $ ref. I don't know what is the reason for this. I really need to know all the properties that are being referenced.
Here is a snippet of my json schema (in the schemas / schema1.json files):
{
"type": "object",
"properties": {
"$ref": "#/definitions/groupedProperties/property1",
"$ref": "#/definitions/groupedProperties/property2"
},
"definitions": {
"groupedProperties": {
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
}
}
}
}
Then I read it into my js file like this (in the test.js file):
var schemas = requireDir('./schemas')
for (var prop in schemas['schema1'].properties) {
console.log(prop)
}
When I iterate over the properties in the schema from my js file, all I see is one $ ref. I assume this is because it thinks the property name is "$ ref" and there can only be unique names. Is there some way I should require this file so that the first $ ref doesn't get confused?
EDIT: My syntax was not passing json schema validators, although I'm not sure why, so instead of struggling with this, I decided to do it a little differently. All I wanted was a way to group certain properties, so I returned the properties to the main schema and changed the definition to just list the names of the properties that go into the group. So now my schematic looks like this:
{
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
},
"definitions": {
"groupedProperties": {
"enum": ["property1", "property2"]
}
}
}
And then in the js file:
var myGroup = (schema.definitions ? schema.definitions.groupedProperties : [])
console.log(myGroup.enum) // [ 'property1', 'property2' ]
source to share
This has nothing to do with require
, object keys are not unique (assuming you can declare them multiple times in the same object), but they are rewritable (just like a variable declared twice is rewritable). You will only get the last value declared with two keys of the same name.
I suggest to give refs a distinctive ID, this will also help clarity when your code expands
source to share
There are many problems with how you reference your definitions.
JSON objects cannot have duplicate properties
All properties of a JSON or JavaScript object are unique. The second will overwrite the first. Let's take a look at the property access syntax to see why. When you read JSON into a JavaScript object, you can try accessing the property $ref
using schema.properties['$ref']
. If there were two, which one (or both) would you get? JavaScript has no mechanism for recognition as it is not allowed.
$ref
must stand alone
When $ref
used in an object, it must be the only property in that object. All other properties will be ignored. This is another reason why two $ref
don't work.
Any members other than "$ ref" in the referenced JSON object MUST be ignored.
$ref
should not be used in properties
$ref
should only be used for schematic references. In this case, the keyword is properties
using $ref
which is an object with schema values. Usage $ref
in this manner is not prohibited in the documentation for the JSON Schema or the JSON Reference, but it is not an idiomatic JSON schema and therefore not supported by most validators. Even if the validator you are using supports references like this, it should be avoided because it is never needed and can lead to schema confusion and difficult to maintain.
Your JSON pointers are wrong
Your JSON pointers don't actually point to the schemas you've defined. The correct pointer would be #/definitions/groupedProperties/properties/property1
.
Positive decisions
This is what you were trying to do.
{
"type": "object",
"properties": {
"property1": { "$ref": "#/definitions/groupedProperties/properties/property1" },
"property2": { "$ref": "#/definitions/groupedProperties/properties/property2" }
},
"definitions": {
"groupedProperties": {
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
}
}
}
}
Here's a cleaner way to include all of yours at groupedProperties
once.
{
"type": "object",
"allOf": [
{ "$ref": "#/definitions/groupedProperties" }
],
"definitions": {
"groupedProperties": {
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
}
}
}
}
Or, since you are only using it for testing purposes, you can flip it so the definition refers to the schema. You can use the definition in your tests without affecting your schema.
{
"type": "object",
"properties": {
"property1": { "type": "string" },
"property2": { "type": "string" }
},
"definitions": {
"groupedProperties": {
"type": "object",
"properties": {
"property1": { "$ref": "#/properties/property1" },
"property2": { "$ref": "#/properties/property2" }
}
}
}
}
source to share