Proposal: Official Support for Extended Use Cases #740
Replies: 4 comments 17 replies
-
I'm currently going through the process of refactoring Corvus.JsonSchema to switch to a keyword/vocabulary based model. This is partly to support vocab in its current state, partly to make it quicker and easier to extend, and partly to make it quicker and easier to grok. The keyword dependencies are the biggest PITA :-) What I've discovered is an interesting layering.
So far there are only three things I've found that I would call "fundamental"
These are fundamental capabilities any keyword may be capable of providing. They will be use-case specific. Typical things an implementation might want to support include "reference resolver", "anchor provider", "subschema provider", "property provider", "numeric validation provider", "string validation provider", "annotator" etc. You may also need to define custom capabilities for a custom vocabulary. The implementation of these capabilities on a keyword is where keyword dependencies manifest. There are two types of dependency
The spec tends towards the former but it may be better to formally define capabilities and talk in terms of capabilities in future. It would make vocab interoperability simpler. For example my
Something that knows how to prioritise and apply the keyword capabilities to an instance for e.g. code generation, validation, annotation etc. |
Beta Was this translation helpful? Give feedback.
-
Another option is to continue to define validation and annotation in Core and simply provide a statement that says these behaviors are optional depending on the application. This would allow something like codegen to be compliant with the spec yet continue to ignore the validation behaviors of all of the keywords. I would want the that allowance to apply wholesale per behavior, though. Implementations shouldn't be able to support validation on some keywords but ignore it for others, so that if a tool claims to support validation, it conforms to all of the validation behavior defined in the spec. |
Beta Was this translation helpful? Give feedback.
-
I think there is sense in your proposal, personally (if I got it right) I would go even more radical. So, as I understand:
Would this look something like: {
"applicator": {
"anyOf": [ "additionalProperties", "allOf", "anyOf", "oneOf", ... ]
},
...
} .. or instead the keywords themselfs may be their $ref *file: {
"format": "iri-reference",
"type": "string",
"$comment": "Fragments not allowed.",
"pattern": "^[^#]*$"
} ? Anyway, I'm in favor of decentralizing
As I see this change, core, applicator and validation keywords can be part of something that we later can refer as |
Beta Was this translation helpful? Give feedback.
-
@gregsdennis off-topic: |
Beta Was this translation helpful? Give feedback.
-
Problem
JSON Schema was originally designed as a JSON validation tool, and as the spec evolved, it has added annotation and even mentions hyper-schema operations.
Since then, users of JSON Schema have invented new ways to utilize JSON Schema beyond validation and annotation of JSON data. However, the specifications continue to be very targeted toward only supporting validation and annotation, making it difficult to create extension specifications that define these new use cases but don't need all of the declared behaviors.
The result is extended functionality without a specification (which means little to no interoperability) that has to resort to partially implementing the specification by leaving out support for the parts that the particular functionality doesn't need.
Proposal
The specifications should be rewritten/reorganized to describe a more abstract evaluation model that enables and supports secondary specifications that define these and future use cases. To facilitate this, the rewrite should focus on defining behaviors and assigning them to keywords rather than fully defining keywords for any particular context.
Core currently explicitly defines the following keyword behaviors:
There is also an implicit behavior:
Of these behaviors, directives and applicability are essential to the JSON Schema evaluation process across all known use cases. These behaviors must remain in Core.
However, since the assertion and annotation behaviors are not common to all use cases, they should be removed from Core and defined in appropriate secondary specification(s).
Schema Evaluation
Currently the spec defines evaluation in terms of having an instance present. However many of these new use cases operate without an instance. In order to support them, we will need to define evaluation outside of the context of having an instance.
Schema evaluation will need to be something along the lines of "applying all behaviors from all keywords present in the schema". Then the behaviors that need an instance, like assertion, are simply defined as such.
By using this evaluation model, Core can define the applicator behavior without an instance, and Validation (and Annotation if that becomes it's own spec) can separately define the assertion behavior as requiring an instance.
This opens the door for non-instance use case specs to directly reference Core while avoiding having to declare some sort of partial support of it.
Split Keyword Definitions
The primary trouble that presents itself with this approach is that many keywords exhibit multiple behaviors which will ultimately be defined across multiple specifications. For example,
properties
exhibits:For a use case like code generation, only applicability is needed (and it's only needed insofar as it can be described without an instance).
If Core defines
properties
, it can only assign the applicability behavior. It can't assign assertion behavior because that behavior isn't defined. The only solution is to have secondary specifications define the assertion and annotation behaviors and then augment those behaviors onto Core's definition ofproperties
.The end result is that if you're working in a validation context,
properties
is not fully defined in a single place; rather its full behavior is defined across both Core and Validation.This makes things easier (read: "possible") for authors of extension specs, but could make things more difficult for tooling authors and even users. I think the solution here is to have good documentation that collates those disparate behavior definitions into a single location.
Tooling Support
Tooling will need to declare the specifications they support, which implicitly declares the behaviors they support.
As an example, a validator would claim support for the Validation spec, which references Core. So the validator must support applicability (inherited from Core) and assertions. However a code generator could claim support for a codegen spec, which references a hypothetical Annotations spec, which in turn references Core, so the code generator would support any behaviors defined by the codegen spec as well as annotation and applicability.
Finally, if the same schema were passed through multiple tools, each tool would interpret the schema in different ways, applying only the set of behaviors that that tool supports. This would allow the same schema to be used by, e.g., a code generator and a validator.
Backward Compatibility
I recognize that from a specification point of view, this is a significant architectural change. However, I believe this can be achieved in a way that preserves functional backward compatibility, even if we do this after the first stable release. The key is preserving requirements. Moving requirements between specs or extracting them to new specs shouldn't affect the functionality of a tool. The tool is still going to claim the same feature set, regardless of the documents that specify those features. At most, they should only need to update documentation to indicate which specifications they support.
My preference would be to make these changes before the first stable release because I think it would be easier, but I'm not convinced it's necessary.
Discussion
The main two things I'd like to discuss here are:
Ultimately, official support for extended use cases is the primary outcome that we want. The proposal above is what makes most sense to me.
There are likely other aspects and implications that I haven't considered yet, so please feel free start threads on those topics as well.
Beta Was this translation helpful? Give feedback.
All reactions