How can i use $ref in json-schema with vue-json-schema-form? - vue.js

I am trying to generate a form which can have multiple recursive fields. I have used https://codepen.io/crickford/pen/ZmJqwd this demo (I am not using any custom component). Whenever i am using "$ref" it ignores it. I am using vue-json-schema-form. Here is the link of github https://github.com/crickford/vue-json-schema-form.
Even if i use "$ref":"#" it's not working.
My Json-schema is valid. Even if i replace the following schema in codepen i don't get expected result, where as it is giving me proper output by editing schema property of the source in this link http://www.alpacajs.org/docs/api/recursive-references.html
I don't know where am I mistaking !! At least in codepen attached schema code should work.
Kindly guide me or share working demo fiddle with me. Thanks in advance.
Here is my schema:
{
"type": "object",
"title": "",
"properties": {
"Namespace": {
"type": "string",
"title": "Namespace ",
"attrs": {
"placeholder": "Namespace",
"title": "Please enter Namespace"
}
},
"Name": {
"type": "string",
"title": "Display Name : ",
"attrs": {
"placeholder": "Display Name",
"title": "Please enter Display name"
}
},
"SubSteps": {
"type": "array",
"title": "SubSteps",
"items": {
"type": "object",
"title": "Sub step",
"$ref": "#/definitions/SubSteps"
}
}
},
"definitions": {
"SubSteps": {
"type": "object",
"title": "SubStep item",
"properties": {
"Namespace": {
"type": "string",
"title": "Namespace ",
"attrs": {
"placeholder": "Namespace",
"title": "Please enter Namespace"
}
},
"Name": {
"type": "string",
"title": "Display Name : ",
"attrs": {
"placeholder": "Display Name",
"title": "Please enter Display name"
}
},
"SubSteps": {
"type": "array",
"title": "SubSteps",
"items": {
"type": "object",
"title": "Sub step",
"$ref": "#/definitions/SubSteps"
}
}
}
}
},
"required": [
"Name"
]
}

It doesn't look like the library in question supports the use of $ref. Therefore you would have to submit an issue and / or pull request to add the functionality you want.

Related

How to properly define an object within definition and reference in multiple places for Json Schema

I am trying to create a json schema wherein I have an object within a definition & this definition is called within multiple places.
I see an error saying UnhandledPromiseRejectionWarning: Error: duplicate type name: Location
I have the below code.
{
"$schema": "http://json-schema.org/draft-07/schema",
"definitions": {
"holiday": {
"description": "A collection of time off associated with the employee.",
"required": [],
"properties": {
"location": {
"type": "object",
"nullable": true,
"title": "Location",
"properties": {
"city": {
"type": "string",
"nullable": true,
"tsType": "string | null",
"description": ""
}
}
}
},
"type": "object"
}
},
"description": "The model for the employee object received on the Ingress API.",
"properties": {
"eventType": {
"avroType": "string",
"enum": ["EMPLOYEE_TIMEOFF_CREATED", "EMPLOYEE_CREATED_OR_UPDATED"],
"tsEnumNames": ["EmployeeTimeOffCreated", "EmployeeCreatedOrUpdated"],
"type": "string"
},
"employeeCreatedOrUpdated": {
"description": "Event data for a employee create request.",
"required": ["code", "firstName", "lastName"],
"properties": {
"code": {
"description": "A unique code for an employee.",
"minLength": 1,
"type": "string"
},
"firstName": {
"description": "This field describes the first name of the employee.",
"minLength": 1,
"type": "string"
},
"middleName": {
"description": "This field describes the middle name of the employee.",
"nullable": true,
"tsType": "string | null",
"type": "string"
},
"lastName": {
"description": "This field describes the last name of the employee.",
"minLength": 1,
"type": "string"
},
"timeOff": {
"description": "A collection of employee time off associated with the employee.",
"items": {
"$ref": "#/definitions/holiday"
},
"nullable": true,
"type": "array"
}
},
"title": "EmployeeCreatedOrUpdated",
"type": "object"
},
"employeeTimeOffCreated": {
"description": "Event data for an employee time off created request.",
"required": ["timeOffCreated", "employeeCode"],
"$id": "https://io.something/v2/employee/employeeTimeOffCreated",
"properties": {
"timeOffCreated": {
"$ref": "#/definitions/holiday"
},
"employeeCode": {
"description": "A unique code for an employee.",
"minLength": 1,
"type": "string"
}
},
"title": "EmployeeTimeOffCreated",
"type": "object"
}
},
"required": ["eventType"],
"title": "EmployeeEvent",
"type": "object"
}
So, I use the holiday definition at two places. I tried to have an id within $ref but that doesn't work. Any help is highly appreciated. Thanks.
Here's your schema reduced to only the parts needed to understand the problem.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"employeeCreatedOrUpdated": {
"type": "object",
"properties": {
"timeOff": {
"type": "array",
"items": { "$ref": "#/definitions/holiday" }
}
}
},
"employeeTimeOffCreated": {
"$id": "https://io.something.ingress/v2/employee/employeeTimeOffCreated",
"type": "object",
"properties": {
"timeOffCreated": { "$ref": "#/definitions/holiday" }
}
}
}
"definitions": {
"holiday": true
}
}
When you use $id in a sub-schema like this, it indicates that the sub-schema is a completely separate schema embedded in the parent schema. Any references inside of the embedded schema are relative the the $id, not the parent schema. So, the reference at "timeOffCreated" expects #/definitions/holiday relative to the embedded schema. There's nothing there, so you get an error.
If you don't need "employeeTimeOffCreated" to be an embedded schema, the easiest thing is to remove $id and your references will work. Otherwise, you can give /definitions/holiday an $id as well and reference with that URI instead.
Embedded schemas are really only good for bundling schemas for distribution. Otherwise, you probably want to maintain separate schemas for each of your entities and just reference other schemas when you need them.
Here's what it would look like neatly bundled. If you want to work on these as separate schemas as suggested, you just need to extract each of the definitions into their own schema.
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://io.something.ingress/v2/employee",
"type": "object",
"properties": {
"employeeCreatedOrUpdated": {
"type": "object",
"properties": {
"timeOff": {
"type": "array",
"items": { "$ref": "./holiday" }
}
}
},
"employeeTimeOffCreated": { "$ref": "./employeeTimeOffCreated" }
}
"definitions": {
"employeeTimeOffCreated": {
"$id": "./employeeTimeOffCreated",
"type": "object",
"properties": {
"timeOffCreated": { "$ref": "./holiday" }
}
},
"holiday": {
"$id": "./holiday",
...
}
}
}
Additional reference: https://json-schema.org/understanding-json-schema/structuring.html#bundling

JSON schema conditional within array based on "oneOf" selection

I'd like to to display a form field based on a selection within an array to be able to dynamically add items based on selection.
What works:
Without array wrapped around this works. See code below:
{
"schema": {
"type": "object",
"properties": {
"accessory": {
"title": "Type",
"type": "string",
"default": "one",
"oneOf": [
{ "title": "First", "enum": ["one"] },
{ "title": "Second", "enum": ["two"] }
],
"required": true
},
"setName": {
"type": "string"
},
"Second Name": {
"type": "string",
"description": "Only displayed if 'two' is selected",
"condition": {
"functionBody": "return model.accessory === 'two';"
}
}
}
}
}
What does not work:
But as soon as I wrap an array around it the condition is not working anymore.
{
"schema": {
"type": "object",
"properties": {
"accessories": {
"title": "Accessories",
"type": "array",
"items": {
"title": "Accessory",
"type": "object",
"properties": {
"accessory": {
"title": "Type",
"type": "string",
"default": "one",
"oneOf": [
{ "title": "First", "enum": ["one"] },
{ "title": "Second", "enum": ["two"] }
],
"required": true
},
"setName": {
"type": "string"
},
"Second Name": {
"type": "string",
"description": "Only displayed if 'two' is selected",
"condition": {
"functionBody": "return model.accessory === 'two';"
}
}
}
}
}
}
}
}
I've also tried the following conditions:
"return model[arrayIndex].accessory === 'two';"
and
"return ['two'].includes(model.accessory);"
This one works:
"Second Name": {
"type": "string",
"description": "Only displayed if 'two' is selected",
"condition": "model.accessories[arrayIndex].accessory=='two'"
}

How to make the root element mandatory in JSONSchema

I have the below JSONSchema, I want the root tag envelope to be mandatory.
Any help would be appreciated.
{
"id": "envelope",
"$schema": "http://json-schema.org/schema#",
"tittle": "Root schema",
"description": "Root schema for all services",
"apiVersion": "1.0",
"type": "object",
"required": [
"metadata",
"data"
],
"properties": {
"metadata": {
"description": "The meta data of the data field",
"type": "object",
"required": [
"sourceSystem",
"deliveryCount",
"retryPeriod",
"correlationId"
],
"properties": {
"sourceSystem": {
"description": "The source System ",
"type": "string"
},
"deliveryCount": {
"description": "Number of times the request tried",
"type": "number",
"default": 0,
"maxLength": 5
},
"retryPeriod": {
"description": "Time set to retry",
"type": "number"
},
"correlationId": {
"description": "Unique id for reference",
"type": "string"
}
}
},
"data": {
"description": "The actual content",
"type": "object"
},
"response": {
"description": "Response",
"type": "string"
}
}
}
The output is
{
"metadata": {
"sourceSystem": "",
"deliveryCount": 1,
"retryPeriod": 30,
"correlationId": ""
},
"data": {}
}
expected output is
{ "envelope" : {
"metadata": {
"sourceSystem": "",
"deliveryCount": 1,
"retryPeriod": 30,
"correlationId": ""
},
"data": {} } }
The "id" attribute does not define any root element, it is used for different purposes.
All you need to do is to define your root schema as an object with a single "envelope" property:
{
"type" : "object"
"properties" : {
"envelope" : {
// here comes your (current) schema
}
}
}

What is the fragment that represent an item in a json schema links array

Given the following two JSON Schema definitions
Schema A
{
"$schema": "http://json-schema.org/draft-04/hyper-schema",
"title": "Member Resource",
"description": "A Member at a group",
"id": "schemata/member",
"definitions": {
"first_name": {
"description": "the first name",
"example": "Severus",
"minLength": 1,
"maxLength": 255,
"type": "string"
},
"last_name": {
"description": "the last name",
"example": "Snape",
"minLength": 1,
"maxLength": 255,
"type": "string"
},
"member_response": {
"description": "Successful response to a show or search request",
"type": "object",
"additionalProperties": false,
"properties": {
"member": { "$ref": "/schemata/member" }
},
"required": ["member"]
},
"error_response": {
"description": "Error response to a show or search request",
"type": "object",
"additionalProperties": false,
"properties": {
"reference_id": {"$ref": "#/definitions/reference_id"},
"errors": {"$ref": "#/definitions/errors"}
},
"required": [errors"]
}
},
"links": [
{
"description": "Retrieve a member",
"href": "/members/{(%23%2Fschemata%member%2Fdefinitions%2Fidentity)}",
"method": "GET",
"rel": "instance",
"title": "Show",
"targetSchema": {
"description": "Result of a get request. Can be either a success or a failure.",
"type": ["object"],
"oneOf": [
{ "$ref": "#/definitions/member_response" },
{ "$ref": "#/definitions/error_response" }
]
}
},
{
"description": "Search for a member",
"href": "/members/search",
"method": "GET",
"rel": "instance",
"schema": {
"description": "The expected payload for a search request",
"type": "object",
"additionalProperties": false,
"properties": {
"first_name": {
"$ref": "#/definitions/first_name"
},
"last_name": {
"$ref": "#/definitions/last_name"
}
},
"required": ["first_name", "last_name"]
},
"targetSchema": {
"description": "Result of a get request. Can be either a success or a failure.",
"type": ["object"],
"oneOf": [
{ "$ref": "#/definitions/member_response" },
{ "$ref": "#/definitions/error_response" }
]
}
"title": "Search"
}
],
}
Schema B
{
"$schema": "http://json-schema.org/draft-04/hyper-schema",
"title": "Member Resource",
"description": "A Member at a group",
"id": "schemata/member",
"definitions": {
"first_name": {
"description": "the first name",
"example": "Severus",
"minLength": 1,
"maxLength": 255,
"type": "string"
},
"last_name": {
"description": "the last name",
"example": "Snape",
"minLength": 1,
"maxLength": 255,
"type": "string"
},
"search_payload": {
"description": "The expected payload for a search request",
"type": "object",
"additionalProperties": false,
"properties": {
"first_name": {
"$ref": "#/definitions/first_name"
},
"last_name": {
"$ref": "#/definitions/last_name"
}
},
"required": ["first_name", "last_name"]
},
"member_response": {
"description": "Successful response to a show or search request",
"type": "object",
"additionalProperties": false,
"properties": {
"member": { "$ref": "/schemata/member" }
},
"required": ["member"]
},
"error_response": {
"description": "Error response to a show or search request",
"type": "object",
"additionalProperties": false,
"properties": {
"reference_id": {"$ref": "#/definitions/reference_id"},
"errors": {"$ref": "#/definitions/errors"}
},
"required": [errors"]
},
"get_response": {
"description": "Result of a get request. Can be either a success or a failure.",
"type": ["object"],
"oneOf": [
{ "$ref": "#/definitions/member_response" },
{ "$ref": "#/definitions/error_response" }
]
}
},
"links": [
{
"description": "Retrieve a member",
"href": "/members/{(%23%2Fschemata%member%2Fdefinitions%2Fidentity)}",
"method": "GET",
"rel": "instance",
"title": "Show",
"targetSchema": {
"$ref": "#/definitions/get_response"
}
},
{
"description": "Search for a member",
"href": "/members/search",
"method": "GET",
"rel": "instance",
"schema": {
"$ref": "#/definitions/search_payload"
},
"targetSchema": {
"$ref": "#/definitions/get_response"
},
"title": "Search"
}
],
}
Both schemas are functionally the same. The difference is that targetSchema is defined inline in schema A but as a ref in schema B.
I use a library to validate the input and output to and API endpoint. For example when testing my APIs I want to validate that the response to each request returns a JSON object that conforms with targetSchema for that API.
JSON::Validator.fully_validate(
schema,
object_to_test,
:fragment => "/path/to/fragment"
)
In order to validate against the targetSchema for the /members/search API defined above I need to be able to reference its targetSchema.
In schema B I can do
JSON::Validator.fully_validate(
schema,
object_to_test,
:fragment => "#/definitions/get_response"
)
Is it possible to do the above for schema A too? i.e. can I reference the actual targetSchema of the search link directly. Perhaps it might look like the following
JSON::Validator.fully_validate(
schema,
object_to_test,
:fragment => "#/links[1]/targetSchema"
)
or
JSON::Validator.fully_validate(
schema,
object_to_test,
:fragment => "#/links/[SOME_WAY_OF_SPECIFYING_THAT_TITLA_EQL_SEARCH"]/targetSchema"
)
Given your schema, you can reference the search link's targetSchema with the following JSON Pointer(1).
#/links/1/targetSchema
Here 1 is the index of the desired item in the links array. This is the only way to reference an item in an array. To precisely answer the question -- there is no way of specifying the item in the array where title equals "search".
Obviously, referencing the targetSchema using an index is fragile. If you add a link to the schema in the wrong place, your code will break. You would be better off if you looped through the links in code and chose the one you need.
You might ask, "Why is it so difficult to reference a link's targetSchema for validation?" The answer is that targetSchema is not intended for validation. targetSchema is intended to be informational only. It's documentation. The only schema that the response should be responsible for conforming to is the one it declares in the response(2). This is one of the core ideas of REST. The client and server are decoupled. The client doesn't make any assumptions about the response it will get. The response itself should have all the information needed to interpret the response and what you can do next.
https://www.rfc-editor.org/rfc/rfc6901
http://json-schema.org/latest/json-schema-core.html#anchor33

Choosing between several property sets in jdorn/json-editor

I have defined two different property sets in my JSON schema and I'm trying to put together an editor that will allow the user to choose one of several property sets and then fill the corresponding properties.
Here is my schema:
{
"type": "object",
"title": "Test Configuration",
"properties": {
"master_property_set": {
"title": "Testing oneOf",
"oneOf": [
{
"type": "object",
"title": "Property set 1",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
}
},
{
"type": "object",
"title": "Property set 2",
"properties": {
"property3": {
"type": "string"
},
"property4": {
"type": "string"
}
}
}
]
}
}
}
Problem is, when I switch to Property set 2, my data still contains property1 and property2 as empty strings and they are displayed in the editor. They should get removed. What am I doing wrong?
The setup can be tested here: http://goo.gl/j91of7
I've found the answer in the docs. Turns out no_additional_properties property of the editor needs to be set to true.
{
"type": "object",
"title": "Test Configuration",
"properties": {
"master_property_set": {
"title": "Testing oneOf",
"oneOf": [
{
"type": "object",
"title": "Property set 1",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
}
},
"additionalProperties":false
},
{
"type": "object",
"title": "Property set 2",
"properties": {
"property3": {
"type": "string"
},
"property4": {
"type": "string"
}
},
"additionalProperties":false
}
]
}
}
}