18

I am writting a json schema to validate my json outputs produced by an exe.The schema being little bit complexe, I have defined some "definitions" that are referenced in properties ("$ref": "#/definitions/...). And using definitions here is all the more important because I have a case where the definition is recursive.

My schema now works well, it validates correctly my json outputs.

Now, I am trying to document the schema correctly using "description" keyword for each property. To develop the schema I use an editor (XMLSpy) that represents the schema graphically. It is very usefull but I face a curious behaviour and I do not know if it is a problem in the editor or if it is me that do not really understand.

Here is a minimal example of json schema to explain my problem:

{
 "$schema": "http://json-schema.org/draft-04/schema#",
 "type": "object",
 "properties": {
  "sourcePath": {
   "$ref": "#/definitions/Path",
   "description": "Here the description where I expected to set it"
  },
  "targetPath": {
   "$ref": "#/definitions/Path",
   "description": "Here another description where I expected to set it to that property of the same kind but whith a different use."
  }
 },
 "additionalProperties": false,
 "definitions": {
  "Path": {
   "description": "Here the descriptiond where it is set by the software",
   "type": "object",
   "properties": {
    "aUsefulProperty": {
     "type": "string"
    },
    "parentPath": {
     "$ref": "#/definitions/Path",
     "description": "Here yest another description where I expected to set it.."
    }
   },
   "required": [
    "aUsefulProperty"
   ],
   "additionalProperties": false
  }
 }
}

When I am trying to add a description to a property, the editor actually add a description inside the definition of the object. In consequence the editor displays this description for both properties "sourcePath" and "targetPath", moreover it displays this description also in "parentPath".

My intent is to have three different descriptions one for each property, (and probably also the definition itself but it is not the problem here). If I add them manually to the json schema, there is no problem but these descriptions does not appear in the graphical editor.

So, I am confused.

Do you think it is a problem with my graphical editor or am I wrong?

Basically, when we use a "$ref" to define a property, is it possible to add some other field as the description or does using a "$ref" imply not using nothing else? In that case, how can I document correctly a property?

I have to provide my json schemas to some partners, that will have to use them as documentation to produce correct json output. So, as far as possible, I would like to provide to them a self-documenting json schema as we can do with XML.

Thanks

SOFe
  • 7,867
  • 4
  • 33
  • 61
Azias
  • 547
  • 1
  • 4
  • 12

2 Answers2

16

Any members other than "$ref" in a JSON Reference object SHALL be ignored.

In order to set a description, you would have to do something like the following example. It might cause other weirdness in you editor, but I'm pretty sure this is the cleanest way to do it.

Original:

{
    "$ref": "#/definitions/Path",
    "description": "Here the description where I expected to set it"
}

Suggested Correction:

{
    "allOf": [{ "$ref": "#/definitions/Path" }],
    "description": "Here the description where I expected to set it"
}
Community
  • 1
  • 1
Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53
  • Thank you for this answer. The problem I see is when I use an operator such as "allOf" or "oneOf" is that the object that use this operator must repeat all properties of combined schemas (or have the possiblity to allow any property, so we cannot add "additionalProperties": false). This is a problem in the current json format, maybe this will be corrected in a futur version. Anyway, it is a bit complex just to add a comment. But now I have the answer I was looking for: when using "$ref", any members other than "$ref" in a JSON Reference object SHALL be ignored. Thank you. – Azias Nov 15 '15 at 10:58
  • I know the problem you are referring to, but you shouldn't run into any issues in this simple case. The problem you describe is why when working with JSON Schema, it is best practice to ignore additional properties rather than explicitly forbid them. – Jason Desrosiers Nov 15 '15 at 23:02
  • I agree in general but here the json will be parsed by a receiver that may crash when there is a unexpected property, so... (I know the solution is to correct the parser). I already use some operator as "allOf" and "anyOf" in my schema but it seems to be too complex juste to add comment. Actually the solution we will probably and finally choose is to generate the json schema from a UML model (that we already have), so the documentation and comments will finally be in the UML. – Azias Nov 17 '15 at 22:39
  • 1
    I agree that the added complexity is probably not worth it for just meta-data unless you are using it to generate something like your documentation. If it were just notes for the dev team, it would just leave it next the `$ref` and let any tools ignore it. Go luck with the UML approach. I'm generally not a fan of generating code, but I hope it works out for you. If you like working in UML, it makes sense to put it at the center of your application like that. – Jason Desrosiers Nov 18 '15 at 18:47
  • 1
    This isn't quite right because "allOf" is an array. It needs to be `"allOf": [ { "$ref": "#/definitions/Path" } ],` – Millie Smith May 23 '19 at 16:33
  • Oops! Thanks for catching that @MillieSmith. I'll edit the answer. – Jason Desrosiers May 23 '19 at 16:45
  • "it would just leave it next the $ref and let any tools ignore it" I like this approach, but I'd tweak it one way. According to the JSON Schema spec, if you want to leave notes for people reading the schema, you use `$comment`, so I'd use that instead for the description of the property meant for people (instead of tooling) to read. – Matt Welke Mar 24 '22 at 18:20
11

Overriding keywords from $refs is allowed under the current JSON Schema draft. The schema in the the original question would be considered valid (depending on the draft...)

From Original Post

    ...
    "properties": {
        "sourcePath": {
            "$ref": "#/definitions/Path",
            "description": "Here the description where I expected to set it"
        },
        "targetPath": {
            "$ref": "#/definitions/Path",
            "description": "Here another description where I expected to set it to that property of the same kind but whith a different use."
        }
    },
   ...

The JSON Schema spec includes an identical example:

From JSON Schema Draft2019

            ....
            "properties": {
                "enabled": {
                    "description": "If set to null, Feature B
                                    inherits the enabled
                                    value from Feature A",
                    "$ref": "#/$defs/enabledToggle"
                }
            }
            ...

The use-case in the question was exactly what the JSON Schema spec describes. In fact, you can override any of the annotation keywords (ie. title, description, default, examples). The example linked above also shows overriding the "default" property.

Unfortunately, the standard makes implementing this optional.

Applications MAY make decisions on which of multiple annotation values to use based on the schema location that contributed the value. This is intended to a allow flexible usage.

So you should test this before relying on it.

Carlo Quinonez
  • 164
  • 1
  • 6
  • 1
    The new `$ref` is logically equivalent to the old `$ref` wrapped in an `allOf`. In case it's not clear, sibling keywords of `$ref` are not limited to annotation keywords and there's still no concept of overriding anything. A property would have two descriptions rather than one overriding the other. However, for annotation keywords only, an implementation MAY choose to use those annotations however they see fit. This creates a loose enough spec that implementations can adopt an overriding type of behavior for annotations without violating the spec. – Jason Desrosiers Nov 12 '19 at 18:16