Handling Next Step JSON Schema Cases
Elements that React Library Handles
The following elements can be given as is, and will handled by the React library.
items
maxLength, minLength, minimum, maximum
pattern
const
enum
$ref
If, Then, Else, Required
Consider the following JSON schema. It contains an enumeration for “country” and depending on the choice, it requires a state or a province.
{
"type": "object",
"properties": {
"country": {
"enum": ["USA", "CA"]
}
},
"if": {
"properties": { "country": { "const": "USA" } }
},
"then": {
"properties": { "state": { "type": "string" } },
"required": [ "state" ]
},
"else": {
"properties": { "province": { "type": "string" } },
"required": [ "province" ]
},
"required": [ "country" ]
}
Suppose that the initial annotations are empty. The following schema will be returned from a next-step job in order to be rendered by the client. The required element will force the JSON schema react library to ensure that there is a choice for the enumeration before moving on to any further step.
{
"type": "object",
"properties": {
"country": {
"enum": ["USA", "CA"]
}
},
"required": [ "country" ]
}
Now suppose that the annotations are updated to contain: “country”: “USA” . Now on a second job to the next-step, the following schema is returned.
{
"type": "object",
"properties": {
"country": {
"enum": ["USA", "CA"]
},
"state": { "type": "string" }
},
"required": [ "state" ]
}
What occurs is that the unconditional fields in the “then” are to be returned due to the annotations present (in this case “country”: “USA” opens up that branch of the schema). To help the client render, we move the fields in the “then” to the “properties” of its immediate JSON schema. And we also move our required element as well so the react library can utilize it to ensure we have an input. If “CA” was chosen earlier, we would return the same schema but with “province” instead.
This can be generalized to an “If + Then” structure and “If + Else”.
Simple AllOf/OneOf/AnyOf
The following schema will be handled by returning the allOf itself, in which the client can render it and also validate that the fields are given values by the user. Therefore this bound JSON schema will also be the same schema returned as the next-step schema.
However, anyOf in the React library seems to indicate that there must only be one option, as it deletes data upon adding to another option. This front-end issue should be addressed by correcting the React Library.
AllOf combined with If, Then, Else
Here we have a country enumeration again. The allOf is used to chain together conditions that we all want to be true for the annotations. In this case, unlike the above simple allOf case, we are unable to just return it to the client as the schema to render as there are conditions inside of it.
Suppose we start with empty annotations. The first next-step schema to be returned may look like the following:
Note that the schema does not provide the allOf because there are no elements in it that can be rendered for the client. Suppose ”country”: “USA”
is updated onto the annotations. A second next-step schema returned from the job may look like the following:
Notice that the “then” of one of the schemas is moved up to the properties and the second schema in the allOf array. The second schema in the array has no properties, so we exclude it.
This can be generalized to oneOf and eventually anyOf (once it is fixed in the React library).
Demonstration of Robustness
The following example is very tedious to follow and is only to be seen as a demonstration of the robustness of our approach to handling the next-step feature using the above ideas recursively.
In short, this schema is an allOf, with an embedded “if + then”, and inside the “then”, we have another allOf, and inside the allOf we have another “if + then”.
The idea is that the first allOf only contains one schema. If we choose “USA” as our country, it will open up the “then”. Inside this “then”, we have another enumeration for a state between “WA” and “OR”. If we choose the state to be “WA”, we open up the “then” inside the schema residing in the next allOf. Inside this final “then”, we mandate that the glasses choice chosen at the beginning be “Yes”.
Below we have the bound JSON schema.
The following is a first next-step schema assuming no annotations present.
Now suppose the state of the annotations become “country”: “USA” and “glasses”: “No”. The second next-step schema will be the following:
Notice that we follow the same procedure of moving the conditioned on properties out of any conditions. Suppose that we add to the annotations the following “state”: “WA”. The 3rd next-step schema will be the following:
And perfectly, the React library will actually invalidate the input you gave in the very first step! This is because you wrote “No” for glasses, but deep down in the logic, we eventually found that you must put “Yes” for “glasses” because you put “WA” as your “state”. Upon changing the choices in the React UI, this complicated schema will self validate on the client side! All of the “If + Then” are also pruned out.
Simple Not
In the case of a simple “not”, we will just return it in the schema. The React library will be able to handle this and validate input on the client side. If the “not” is inside of “if + then” structures, we will handle it in the same way handle properties in those structures.