I know that fields listed in a json schema object have no defined order, since they are not an array, but I am looking for a way to be able to display them in the proper order in my application UI.
Workarounds I have found so far include things like using a different serializer, or even hard-coding a number into the field name.
I would like to come up with something that works with my current setup.
Hibernate, Spring Boot, and a react-app front end.
given this GET request:
/profile/personEntities
with header: Accept: application/schema+json
I will receive this:
{
"title": "Person entity",
"properties": {
"birthday": {
"title": "Birthday",
"readOnly": false,
"type": "string",
"format": "date-time"
},
"lastName": {
"title": "Last name",
"readOnly": false,
"type": "string"
},
"address": {
"title": "Address",
"readOnly": false,
"type": "string",
"format": "uri"
},
"firstName": {
"title": "First name",
"readOnly": false,
"type": "string"
},
"email": {
"title": "Email",
"readOnly": false,
"type": "string"
},
"cellPhone": {
"title": "Cell phone",
"readOnly": false,
"type": "string"
}
},
"requiredProperties": [
"firstName",
"lastName"
],
"definitions": {},
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#"
}
I have tried adding #JsonProperty(index=2) to the field, but nothing changes.
Thank you much for any tips.
If you're using Jackson to handle your serialization/deserialization you can use #JsonPropertyOrder - from their docs:
// ensure that "id" and "name" are output before other properties
#JsonPropertyOrder({ "id", "name" })
// order any properties that don't have explicit setting using alphabetic order
#JsonPropertyOrder(alphabetic=true)
See: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonPropertyOrder.html
Related
Lets say I have two schemas defined as follows -
ADDRESS_CLASS_SCHEMA_DEFINITION = {
"title": "Address",
"type": "object",
"properties": {
"country_code": {
"$ref": "#/definitions/CountryCode"
},
"city_code": {
"title": "City Code",
"type": "string"
},
"zipcode": {
"title": "Zipcode",
"type": "string"
},
"address_str": {
"title": "Address Str",
"type": "string"
}
},
"required": [
"country_code",
"city_code",
"zipcode"
],
"definitions": {
"CountryCode": {
"title": "CountryCode",
"description": "An enumeration.",
"enum": [
"CA",
"USA",
"UK"
],
"type": "string"
}
}
}
EMPLOYEE_CLASS_SCHEMA_DEFINITION = {
"title": "Employee",
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "integer"
},
"name": {
"title": "Name",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"telephone": {
"title": "Telephone",
"type": "string"
},
"address": {
"$ref": "#/definitions/Address"
}
},
"required": [
"id",
"name",
"email"
],
"definitions": {
"Address": ADDRESS_CLASS_SCHEMA_DEFINITION
}
}
I'm trying to re-use sub-schema definitions by defining a constant and referencing them individually in definitions (for example address-schema is referenced through constant in employee-schema definition). This approach works for individual schemas, however there seems to be a json-pointer path issue for Employee schema - #/definitions/CountryCode wouldn't resolve in Employee schema. I was assuming that #/definitions/CountryCode would be a relative path on Address schema as its scope is defined on a sub-schema, but my understanding seems wrong. I can make it work by flattening out like below, however I donot want to take this route -
{
"title": "Employee",
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "integer"
},
"name": {
"title": "Name",
"type": "string"
},
"email": {
"title": "Email",
"type": "string"
},
"telephone": {
"title": "Telephone",
"type": "string"
},
"address": {
"$ref": "#/definitions/Address"
}
},
"required": [
"id",
"name",
"email"
],
"definitions": {
"CountryCode": {
"title": "CountryCode",
"description": "An enumeration.",
"enum": [
"CA",
"USA",
"UK"
],
"type": "string"
},
"Address": {
"title": "Address",
"type": "object",
"properties": {
"country_code": {
"$ref": "#/definitions/CountryCode"
},
"city_code": {
"title": "City Code",
"type": "string"
},
"zipcode": {
"title": "Zipcode",
"type": "string"
},
"address_str": {
"title": "Address Str",
"type": "string"
}
},
"required": [
"country_code",
"city_code",
"zipcode"
]
}
}
}
I'm wondering how to fix this, I've briefly looked into jsonschema-bundling and using $id but from best practices it seems like the general recommendation is to use $id when dealing with URI's alone. Would like to know about best practices and how to fix this problem, would also appreciate if someone can point me on how to use $id correctly (for example, constant based approach seems to work when I provide identifiers like $id: Address, $id: Employee). Thanks in advance.
JSON Schema implementations work in JSON land. When you combine your schemas in your example above, presumably in javascript/node.js, by the time it gets to the JSON Schema implementation for validation execution, any knowledge that there were separate schemas is lost. (It's generally not considered that this approach is the best approach.)
The EASY fix here SHOULD be just to define $id in each of the roots of your schemas. These should be a fully qualfied URI. It doesn't really matter what they are at this point. They could be https://example.com/a and https://example.com/b. Then, in the primary schema, you can do $ref: https://example.com/b.
Implementations should provide you with a way to load in your other/non-primary schemas so the $id values can be stored in an index. Using $id in your other schema with a fully qualified URI will signify a "resource boundary".
https://json-schema.hyperjump.io is the only web playground to support multiple files/schemas/"Schema Resources", so you can test this out there to confirm your expectations.
Not all implementations make it easy or even provide a means to import your other schemas, but they should.
If you have follow up questions, feel free to leave a comment, or join the JSON Schema slack server if it would be off-topic for StackOverflow.
I have a JSON object like:
{
"result": [
{
"name" : "abc",
"email": "abc.test#mail.com"
},
{
"name": "def",
"email": "def.test#mail.com"
},
{
"name": "xyz",
"email": "abc.test#mail.com"
}
]
}
and schema for this:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/object1607582431.json",
"title": "Root",
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"$id": "#root/result",
"title": "Result",
"type": "array",
"default": [],
"uniqueItems": true,
"items": {
"$id": "#root/result/items",
"title": "Items",
"type": "object",
"required": [
"name",
"email"
],
"properties": {
"name": {
"$id": "#root/result/items/name",
"title": "Name",
"type": "string"
},
"email": {
"$id": "#root/result/items/email",
"title": "Email",
"type": "string"
}
}
}
}
}
}
I am looking for an option to check uniqueness for email irrespective of name. How I can validate that every email should be unique?
You can't. There are no keywords that let you compare one particular data value against another, other than uniqueItems, which compares an array element in toto against another.
The JsonSchema specification does not currently support this.
You can see the active GitHub issue here: https://github.com/json-schema-org/json-schema-vocabularies/issues/22
However, there are various extensions of JsonSchema that do validate unique fields within lists of objects.
If you happen to be using Python you can use the package (I created) JsonVL. It can be installed with pip install jsonvl and then run with jsonvl data.json schema.json.
Code examples in the GitHub repo: https://github.com/gregorybchris/jsonvl
I have the following schema:
{
"$schema": "http://json-schema.org/schema#",
"$id": "http://api.hobnob.social/schemas/users/create.json",
"title": "Create User Schema",
"description": "For validating client-provided create user object",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"password": { "type": "string" },
"profile": { "$ref": "profile.json#" }
},
"required": ["email", "password"],
"additionalProperties": false
}
{
"$schema": "http://json-schema.org/schema#",
"$id": "http://api.hobnob.social/schemas/users/profile.json",
"title": "User Profile Schema",
"description": "For validating client-provided user profile object when creating and/or updating an user",
"type": "object",
"properties": {
"bio": { "type": "string" },
"summary": { "type": "string" },
"name": {
"type": "object",
"properties": {
"first": { "type": "string" },
"last": { "type": "string" },
"middle": { "type": "string" }
},
"additionalProperties": false
}
},
"additionalProperties": false
}
I am using ajv to validate against it. I am getting the expected results in almost all cases. But when validating a json with either the bio or summary fields included (with type of string), no response comes from ajv at all.
E.g. I attempt to validate
{
"email": "e#ma.il",
"password": "password",
"profile": {
"name": {
"first": "firstname"
},
"bio":"this is a bio"
}
}
and no response at all comes back.
I tried consolidating the schema but that made no difference. I'm hoping I have made some simple beginner mistake that someone may spot! I have spent many hours trying to work out what is going wrong, but after all my debugging I am no further forward.
I got this working somehow, but not sure why it started working.
In my test script I added a line to delete the test index from elasticsearch. After that, all tests passed. I then removed the new line from my test script to see if it would stop working again, but it didn't.
I'm guessing the problem was somehow related to elasticsearch...
Can I have a custom specifier/attribute like "required" keyword to decorate my Json schema fields with custom specifications.
Like for example:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "integer"
},
"name": {
"description": "Name of the product",
"type": "string"
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"**credit-card**": {
"**type**": "**number**",
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": ["id", "name", "price"],
"**confidential**" : ["**credit-card**"]
}
Can I have a special keyword called "confidential" to make sure that "credit-card" should not be revealed and/or masked? Does the schema standards allow for such custom metadata keywords?
It depends on the library you will use to execute the validation. I've used AJV, it allows you to define custom keywords, you can find more information about it here.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "number"
},
"name": {
"type": "string"
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"dimensions": {
"type": "object",
"properties": {
"length": {"type": "number"},
"width": {"type": "number"},
"height": {"type": "number"}
},
"required": ["length", "width", "height"]
},
"warehouseLocation": {
"description": "Coordinates of the warehouse with the product",
"$ref": "http://json-schema.org/geo"
}
},
"required": ["id", "name", "price"]
}
}
In the above Json schema "dimensions"is of "type": "object" , is type optional , if "type" is not specified should i assume it to be object. Could not find anything in specs related to optional elements.
https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-03#section-5.1
If the property is not defined or is not in this list, then any
type of value is acceptable.
type is optional, ANY value is acceptable if type is omitted.
I think it is not optional. As you can see in the meta-schema below, the property "type" has no default value:
http://json-schema.org/schema
Also in my JSON Schema library NJsonSchema I set the type to None instead of Object. Check out the TypeRaw property:
https://github.com/rsuter/NJsonSchema/blob/master/NJsonSchema/JsonSchema4.Serialization.cs
When the default value is set to Object a lot more tests from the JSON Schema test suite fail. Maybe you can find a definite answer in this JSON Schema test suite:
https://github.com/json-schema/JSON-Schema-Test-Suite