How to extract patternProperties and additionalProperties from Rapidjson DOM - jsonschema

I have a json schema similar to:
{
"properties": {
...
},
"patternProperties": {
"^.*$": {
"anyOf": [
{"type": "string"},
{"type": "null"}
]
}
}
I am using Rapidjson to parse/write json files following the above schema.
My question is :
How to get/set data corresponding to the 'patternProperties' and 'additionalProperties' from the rapidjson DOM?

Related

How to ref JSON schema definition of type array with anyOf definition in other files

I have a jsonschema definition definition-1.json like below. I have a property called inputs of type array which refers anyOf definitions like
"inputs": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "#/definitions/stringParameter"
},
{
"$ref": "#/definitions/numberParameter"
},
{
"$ref": "#/definitions/booleanParameter"
},
{
"$ref": "#/definitions/jsonParameter"
},
{
"$ref": "#/definitions/fileParameter"
}
]
}
}
Then the parameter definitions defined like below in the same jsonschema definition-1.json
"definitions": {
"stringParameter": {
"type": "object",
"required": [
"name",
"description",
"datatype"
]
}
...
}
Now I want to reference this parameter definitions in my other schema dummy-1.json like below
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "dummy-1.json",
"allOf": [
{
"type": "object",
"required": [
"definition_data"
],
"properties": {
"definition_data": {
"type": "object",
"required": [
"inputs"
],
"properties": {
"type": "array",
"inputs": {
"items": {
"allOf": [
{
"prop1": {
"$ref": "#/definitions/stringParameter"
}
},
{
"prop2": {
"$ref": "#/definitions/numberParameter"
}
}
]
}
}
}
}
}
},
{
"type": "object",
"properties": {
"definition_data": {
"$ref": "definition-1.json"
}
}
}
]
}
This doesn't looks like working. prop1 will validate successfully for any properties part of other parameter definition too , even though in dummy-1.json I explicitly referred #/definitions/stringParameter .
I can understand inputs in definition-1.json accepts anyOf all parameter definitions. But want to know how we can achieve 1:1 parameter definition mapping for dummy-1.json .
If my understanding is correct, you want to refer from dummy-1.json to subschemas defined in definitions-1.json. To do that, you have to specify the URI of definition-1.json and append the pointer of the subschema in it, like:
dummy-1.json:
{
"$ref": "uri-of-definitions-1.json#/definitions/stringParameter"
}
Note that the URI to be set is quite specific to the json schema library you are using. Usually an absolute https:// URL works, but it isn't always convenient to work with. Maybe a relative path can work for you as well (like ./definition-1.json#/definitions/stringParameter)

Deeply nested unevaluatedProperties and their expectations

I have been working on my own validator for JSON schema and FINALLY have most of how unevaluatedProperties are supposed to work,... I think. That's one tricky piece there! However I really just want to confirm one thing. Given the following schema and JSON, what is the expected outcome... I have tried it with a https://www.jsonschemavalidator.net and gotten an answer, but I was hoping I could get a more definitive answer.
The focus is the faz property is in fact being evaluated, but the command to disallow unevaluatedProperties comes from a deeply nested schema.
Thoguhts?
Here is the schema...
{
"type": "object",
"properties": {
"foo": {
"type": "object",
"properties": {
"bar": {
"type": "string"
}
},
"unevaluatedProperties": false
}
},
"anyOf": [
{
"properties": {
"foo": {
"properties": {
"faz": {
"type": "string"
}
}
}
}
}
]
}
Here is the JSON...
{
"foo": {
"bar": "test",
"faz": "test"
}
}
That schema will successfully evaluate against the provided data. The unevaluatedProperties keyword will be aware of properties evaluated in subschemas of adjacent keywords, and is evaluated after all other applicator keywords, so it will see the annotation produced from within the anyOf subschema, also.
Evaluating this keyword is easy if you follow the specification literally -- it uses annotations to decide what to do. You just need to make sure that all keywords either produce annotations correctly or propagate annotations correctly that were produced by other keywords, and then all the information is available to generate the correct result.
The result produced by my implementation is:
{
"annotations" : [
{
"annotation" : [
"faz"
],
"instanceLocation" : "/foo",
"keywordLocation" : "/anyOf/0/properties/foo/properties"
},
{
"annotation" : [
"foo"
],
"instanceLocation" : "",
"keywordLocation" : "/anyOf/0/properties"
},
{
"annotation" : [
"bar"
],
"instanceLocation" : "/foo",
"keywordLocation" : "/properties/foo/properties"
},
{
"annotation" : [],
"instanceLocation" : "/foo",
"keywordLocation" : "/properties/foo/unevaluatedProperties"
},
{
"annotation" : [
"foo"
],
"instanceLocation" : "",
"keywordLocation" : "/properties"
}
],
"valid" : true
}
This is not an answer but a follow up example which I feel is in the same vein. I feel this guides us to the answer.
Here we have a single object being validated. But the unevaluated command resides in two different schemas each a part of a different "adjacent keyword subschemas"(from the core spec http://json-schema.org/draft/2020-12/json-schema-core.html#rfc.section.11)
How should this be resolved. If all annotations must be evaluated then in what order do I evaluate? The oneOf first or the anyOf? According the spec an unevaluated command(properties or items) generate annotation results which means that that result would affect any other unevaluated command.
http://json-schema.org/draft/2020-12/json-schema-core.html#unevaluatedProperties
"The annotation result of this keyword is the set of instance property names validated by this keyword's subschema."
This is as far as I am understanding the spec.
According to the two validators I am using this fails.
Schema
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"foo": {
"type": "string"
}
},
"oneOf": [
{
"properties": {
"faz": {
"type": "string"
}
},
"unevaluatedProperties": true
}
],
"anyOf": [
{
"properties": {
"bar": {
"type": "string"
}
},
"unevaluatedProperties": false
}
]
}
Data
{
"bar": "test",
"faz": "test",
}

Validate using a specific definition with ajv

I have a JSON Schema file describing my API. It consists of some definitions as well as some vestigial parts from codegen that I'd like to ignore (the properties and required fields):
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"CreateBook": {
"properties": {
"title": {"type": "string"},
"author": {"type": "string"},
"numPages": {"type": "number"}
},
"required": ["title", "author"]
},
"CreateShelf": {
"properties": {
"books": {"type": "array", "items": {"type": "string"}}
},
"required": ["books"]
}
},
"properties": {
"/api/create-book": {
"properties": {"type": {"post": {"$ref": "#/definitions/CreateBook"}}},
"required": ["post"],
"type": "object"
},
"/api/create-shelf": {
"properties": {"type": {"post": {"$ref": "#/definitions/CreateShelf"}}},
"required": ["post"],
"type": "object"
}
},
"required": ["/api/create-book", "/api/create-shelf"],
"type": "object"
}
I'd like to validate requests according to the definitions. I'd like to completely ignore the properties and required fields, which describe the shape of the API itself, not the individual requests.
Given what I expect to be a CreateBook request and this JSON schema, how should I validate it?
Here's what I tried:
const ajv = new Ajv();
const validate = ajv.compile(jsonSchema);
const body = {
author: 'Roald Dahl',
numPages: 234,
// missing title
};
if (!validate(body, '#/definitions/CreateBook')) {
console.log(validate.errors);
}
This logs:
[
{
keyword: 'required',
dataPath: '#/definitions/CreateBook',
schemaPath: '#/required',
params: { missingProperty: '/api/create-book' },
message: "should have required property '/api/create-book'"
}
]
So it's ignoring the dataPath parameter ('#/definitions/CreateBook'). What's the right way to do this? Do I need to create a new schema for every request type?
If you use addSchema instead of compile to compile the schema, you can specify a fragment.
const ajv = new Ajv();
ajv.addSchema(jsonSchema);
const validate = ajv.getSchema("#/definitions/CreateBook");
const body = {
author: 'Roald Dahl',
numPages: 234,
// missing title
};
if (!validate(body)) {
console.log(validate.errors);
}

How to use definitions from external files in JSON Schema?

I'm trying to import the definitions from another json schema using $ref but getting the following error:
can't resolve reference ../base/definitions.schema.json#/definitions/datetime from id #
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"datetime": {
"type": "string"
},
"name": {
"type": "string"
},
}
}
{
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"active": {"type": "boolean"},
"created_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" },
"name": { "$ref": "../base/base/definitions.schema.json#/definitions/name" },
"updated_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" }
},
"required": ["name"],
"type": "object"
}
Directory structure:
api
-- base
-- definitions.schema.json
-- country
-- country.schema.json
I have tried several combinations by using an absolute path, a file url and several other combinations of the path. Not sure what's going on.
Schema validator: ajv#5.1.1
You need to add schemas using "addSchema" method. $ref is resolved relative to "id" attribute ("$id" in draft-06), ajv doesn't (and can't) use file paths.
EDIT: added $ref section to docs.

Is it possible to inline JSON schemas into a JSON document? [duplicate]

For example a schema for a file system, directory contains a list of files. The schema consists of the specification of file, next a sub type "image" and another one "text".
At the bottom there is the main directory schema. Directory has a property content which is an array of items that should be sub types of file.
Basically what I am looking for is a way to tell the validator to look up the value of a "$ref" from a property in the json object being validated.
Example json:
{
"name":"A directory",
"content":[
{
"fileType":"http://x.y.z/fs-schema.json#definitions/image",
"name":"an-image.png",
"width":1024,
"height":800
}
{
"fileType":"http://x.y.z/fs-schema.json#definitions/text",
"name":"readme.txt",
"lineCount":101
}
{
"fileType":"http://x.y.z/extended-fs-schema-video.json",
"name":"demo.mp4",
"hd":true
}
]
}
The "pseudo" Schema note that "image" and "text" definitions are included in the same schema but they might be defined elsewhere
{
"id": "http://x.y.z/fs-schema.json",
"definitions": {
"file": {
"type": "object",
"properties": {
"name": { "type": "string" },
"fileType": {
"type": "string",
"format": "uri"
}
}
},
"image": {
"allOf": [
{ "$ref": "#definitions/file" },
{
"properties": {
"width": { "type": "integer" },
"height": { "type": "integer"}
}
}
]
},
"text": {
"allOf": [
{ "$ref": "#definitions/file" },
{ "properties": { "lineCount": { "type": "integer"}}}
]
}
},
"type": "object",
"properties": {
"name": { "type": "string"},
"content": {
"type": "array",
"items": {
"allOf": [
{ "$ref": "#definitions/file" },
{ *"$refFromProperty"*: "fileType" } // the magic thing
]
}
}
}
}
The validation parts of JSON Schema alone cannot do this - it represents a fixed structure. What you want requires resolving/referencing schemas at validation-time.
However, you can express this using JSON Hyper-Schema, and a rel="describedby" link:
{
"title": "Directory entry",
"type": "object",
"properties": {
"fileType": {"type": "string", "format": "uri"}
},
"links": [{
"rel": "describedby",
"href": "{+fileType}"
}]
}
So here, it takes the value from "fileType" and uses it to calculate a link with relation "describedby" - which means "the schema at this location also describes the current data".
The problem is that most validators do not take any notice of any links (including "describedby" ones). You need to find a "hyper-validator" that does.
UPDATE: the tv4 library has added this as a feature
I think cloudfeet answer is a valid solution. You could also use the same approach described here.
You would have a file object type which could be "anyOf" all the subtypes you want to define. You would use an enum in order to be able to reference and validate against each of the subtypes.
If the sub-types schemas are in the same Json-Schema file you don't need to reference the uri explicitly with the "$ref". A correct draft4 validator will find the enum value and will try to validate against that "subschema" in the Json-Schema tree.
In draft5 (in progress) a "switch" statement has been proposed, which will allow to express alternatives in a more explicit way.