I have an API which returns response in the format
[
{"id": 12345,
"value": "some_string",
"practice_id": "12344"},
{"id": 12346,
"value": "some_other_string",
"practice_id": "12345"},
]
I am testing that the response validates a specific JSON-Schema, and my schema test is
response.body.should.have.schema({
type: 'array',
required: ['id', 'value', 'practice_id'],
properties: {
id: {
type: 'number',
},
value: {
type: 'string',
},
practice_id: {
type: 'string',
minLength: 5,
}
}
});
The issue is that the test passes even if I change the type of id to string or change the value of practice_id to number, which is not correct.
What am I doing wrong here? I am using Postman-BDD to validate the responses.
I guess your schema should be more like this:
{
"type": "array",
"items":
{
"required":
[
"id",
"value",
"practice_id"
],
"properties":
{
"id":
{
"type": "number"
},
"value":
{
"type": "string"
},
"practice_id":
{
"type": "string",
"minLength": 5
}
}
}
}
You are missing the "items" keywords to actually define the content of the array. And this schema also gives an error in JSONBuddy on validating some sample data:
Related
how can i get the properties of my object?
hello i'm trying to get the properties with the array of ids but my console say undefined
i try with this
console.log(data.entry.properties)
it show me the two properties "pm:title" and "pm:taggable", but i only want the "pm:taggable" with his array
i try something like
console.log(data.entry.properties["pm:taggable"])
but it show me: properties of undefined (reading 'cm:taggable')
i´d like to show in console only the the array of ids 'cm:taggable'
data: {
entry: {
isFile: true,
createdByUser: [Object],
content: [Object],
aspectNames: [Array],
isFolder: false,
modifiedByUser: [Object],
name: 'Cine',
properties: [Object]
}
}
the properties have a object with
"properties": {
"pm:title": "Scary movie",
"pm:taggable": [
"a112a22463563-9c56-428f-a4ac-a2341as2a",
"2545ds467-62e5-448d-a062-34sf466dfs",
"a3af33-2b8d-40c3-98c3-3awfsa356a"
],
"cm:description": "Description"
}
Strange, it works for me. Perhaps you are incorrectly referring to the parent element, skipping the variable name?
const resourceData = {
"data": {
"entry": {
"id": "string",
"name": "string",
"nodeType": "string",
"isFolder": true,
"isFile": true,
"isLocked": false,
"modifiedAt": "2022-09-23T18:25:21.236Z",
"modifiedByUser": {
"displayName": "string",
"id": "string"
},
"aspectNames": [
"string"
],
"properties": {},
"allowableOperations": [
"string"
],
"properties": {
"pm:title": "title",
"pm:taggable": [
"a112a22463563-9c56-428f-a4ac-a2341as2a",
"2545ds467-62e5-448d-a062-34sf466dfs",
"a3af33-2b8d-40c3-98c3-3awfsa356a"
],
"cm:description": "Description"
}
}
}
}
console.log(resourceData.data.entry.properties['pm:title'])
console.log(resourceData.data.entry.properties['pm:taggable'])
console.log(resourceData.data.entry.properties['cm:description'])
const personData= {
name: null,
email: 'test#gmail.com'
}
const schema = {
instance: personData,
schema: {
type: "object",
anyOf: [
{ required: ["name", "email"] }
]
}
}
I want a schema which will validate the object and from object any of the key value (name or email) where one of them must be not null.
It looks like you're confused between "undefined" and "null", which are distinctly different. (I've now edited your question in light of your comment on my answer.)
The required keyword makes sure that a key is "defined" in the applicable object. The value is irrelevant, and may be null.
If you want to define the TYPE of a property, you have to use the type keyword.
anyOf must be an array of schemas where at least one of them must be true.
You've defined one subschema in the anyOf, and as a result, it must be true as a whole, making both items in the required array, required.
You want to define multiple schemas under your anyOf, where one each schema defines that a property must be of a specific type (null is a type).
{
"type": "object",
"required": ["name", "email"],
"anyOf": [
{
"properties": {
"name": {
"type": "string"
}
}
}, {
"properties": {
"email": {
"type": "string"
}
}
}
]
}
You can solve this by placing the 'required' property under the anyof list
{
"type": "object",
"anyOf": [
{
"required": ["name"],
"properties": {
"name": {
"type": "string"
}
}
}, {
"required": ["email"],
"properties": {
"email": {
"type": "string"
}
}
}
]
}
The required attribute means you must have a property in data. It may be nullable, though. To exclude null values make sure that anyOf properties you need are not null:
"anyOf": [
{
"properties": {
"name": {
"not": {
"type": "null"
}
}
}
},
{
"properties": {
"email": {
"not": {
"type": "null"
}
}
}
}
]
Full version goes below:
{
"type": "object",
"properties": {
"name": {
"type": [
"string",
"null"
]
},
"email": {
"type": [
"string",
"null"
]
}
},
"required": [
"name",
"email"
],
"anyOf": [
{
"properties": {
"name": {
"not": {
"type": "null"
}
}
}
},
{
"properties": {
"email": {
"not": {
"type": "null"
}
}
}
}
]
}
Given:
Say that I am defining a schema for Contacts. But, I can have "Primary Contact", "Student" or one who is both; and different properties that go with all three choices. The contact types are defined in an array of contact_type: [ "Primary Contact", "Student" ] which can be either one, or both.
Say that the fields are as such per contact type:
If Primary Contact, then I want phone_number
If Student, then I want first_name
If Student and Primary Contact then I want phone_number and first_name
Usage
I use Ajv library to validate in Node.js using a code like such:
function validator(json_schema){
const Ajv = require('ajv');
const ajv = new Ajv({allErrors: true});
return ajv.compile(json_schema)
}
const validate = validator(json_schema);
const valid = validate(input);
console.log(!!valid); //true or false
console.log(validate.errors)// object or null
Note: I've had trouble with allErrors: true while using anyOf for this, and I use the output of allErrors to return ALL the missing/invalid fields back to the user rather than returning problems one at a time. Reference: https://github.com/ajv-validator/ajv/issues/980
Schema
I have written the following schema and it works if I do either "Student" or "Primary Contact" but when I pass both, it still wants to validate against ["Student"] or ["Primary Contact"] rather than both.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": [],
"properties": {},
"allOf": [
{
"if": {
"properties": {
"contact_type": {
"contains": {
"allOf": [
{
"type": "string",
"const": "Primary Contact"
},
{
"type": "string",
"const": "Student"
}
]
}
}
}
},
"then": {
"additionalProperties": false,
"properties": {
"contact_type": {
"type": "array",
"items": [
{
"type": "string",
"enum": [
"Student",
"Primary Contact"
]
}
]
},
"phone": {
"type": "string"
},
"first_name": {
"type": "string"
}
},
"required": [
"phone",
"first_name"
]
}
},
{
"if": {
"properties": {
"contact_type": {
"contains": {
"type": "string",
"const": "Student"
}
}
}
},
"then": {
"additionalProperties": false,
"properties": {
"contact_type": {
"type": "array",
"items": [
{
"type": "string",
"enum": [
"Student",
"Primary Contact"
]
}
]
},
"first_name": {
"type": "string"
}
},
"required": [
"first_name"
]
}
},
{
"if": {
"properties": {
"contact_type": {
"contains": {
"type": "string",
"const": "Primary Contact"
}
}
}
},
"then": {
"additionalProperties": false,
"properties": {
"contact_type": {
"type": "array",
"items": [
{
"type": "string",
"enum": [
"Student",
"Primary Contact"
]
}
]
},
"phone": {
"type": "string"
}
},
"required": [
"phone"
]
}
}
]
}
Example Valid Inputs:
For just ["Primary Contact"]:
{
"contact_type":["Primary Contact"],
"phone":"something"
}
For just ["Student"]:
{
"contact_type":["Student"],
"first_name":"something"
}
For ["Primary Contact", "Student"]
{
"contact_type":["Primary Contact", "Student"],
"phone":"something",
"first_name":"something"
}
Question:
I would like this to validate even if allErrors: true, is this possible? If not, how should I change the schema?
Footnotes
I don't want to change the "contact_type" from being an array unless it is the last resort. (it is a requirement, but can be broken only if there's no other way)
I can't allow any additionalItems, therefore I'm fully defining each object in the if statements although contact_type is common. If I move contact_type out, then I get error messages about passing contact_type as an additionalItem (it looks at the if statement's properties and doesn't see contact_type when it's taken out to the common place). This is why my initial properties object is empty.
Here's how I might go about solving the validation issue: https://jsonschema.dev/s/XLSDB
Here's the Schema...
(It's easier if you try to break up concerns)
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
First, we want to define our conditional checking subschemas...
"definitions": {
"is_student": {
"properties": {
"contact_type": {
"contains": {
"const": "Student"
}
}
}
},
"is_primay_contact": {
"properties": {
"contact_type": {
"contains": {
"const": "Primary Contact"
}
}
}
}
},
Next, I'm assuming you always want contact_type
"required": ["contact_type"],
"properties": {
"contact_type": {
"type": "array",
"items": {
"enum": ["Primary Contact", "Student"]
}
},
And we need to define all the allowed properties in order to prevent additional properties. (draft-07 cannot "see through" applicator keywords like allOf. You can with draft 2019-09 and beyond, but that's another story)
"phone": true,
"first_name": true
},
"additionalProperties": false,
Now, we need to define our structural constraints...
"allOf": [
{
If the contact is a student, first name is required.
"if": { "$ref": "#/definitions/is_student" },
"then": { "required": ["first_name"] }
},
{
If the contact is a primary contact, then phone is required.
"if": { "$ref": "#/definitions/is_primay_contact" },
"then": { "required": ["phone"] }
},
{
However, additionally, if the contact is both a student and a primary contact...
"if": {
"allOf": [
{ "$ref": "#/definitions/is_student" },
{ "$ref": "#/definitions/is_primay_contact" }
]
},
Then we require both phone and first name...
"then": {
"required": ["phone", "first_name"]
},
Otherwise, one of phone or first name is fine (which one is covered by the previous section)
"else": {
"oneOf": [
{
"required": ["phone"]
},
{
"required": ["first_name"]
}
]
}
}
]
}
I'm not convinced this is the cleanest approach, but it does work for the requirements you've provided.
As for getting validation errors you can pass back to your END user... given the conditional requirements you lay out, it's not something you can expect with pure JSON Schema...
Having said that, ajv does provide an extension to add custom error messages, which given the way I've broken the validation down into concerns, might be useable to add custom errors as you're looking to do (https://github.com/ajv-validator/ajv-errors).
Hello I am new in Loopback
Here I am using loopback, mongodb, currently I have two collection with me, i.e. Company and Employee.
In employee collection, I am referring the company as a foreign key in employee table(means collection in mongo).
Company.json
"properties": {
"_id": {
"type": "number"
},
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
},
Employee.json
"properties": {
"name": {
"type": "string",
"required": true
},
"age": {
"type": "number",
"required": true
},
"department": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
},
"salary": {
"type": "number",
"required": true
},
"componyId": {
"type": "objectid",
"required": true
}
},
"validations": [],
"relations": {
"compony": {
"type": "belongsTo",
"model": "Company",
"foreignKey": "componyId"
}
},
Please let me where I am get in wrong here...
empoyee.js
module.exports = function(Employee) {
console.log('Employee....:', Employee);
Employee.findSalary = function(value, cb) {
console.log('Employee value....:', value, cb);
Employee.find({
where: {
salary: {
gte: value,
},
},
include: {
relation: 'compony',
},
}, cb);
};
Employee.remoteMethod('findSalary', {
accepts: {
arg: 'salary',
type: 'number',
},
returns: {
arg: 'salarys',
type: 'array',
},
http: {
path: '/find-salary',
verb: 'get',
},
});
};
Thanks,
I think you should remove this part:
"componyId": {
"type": "objectid",
"required": true
}
and
include: {
relation: 'compony',
}
could be just
include: 'compony'
and I think you have a typo in 'compony' but you consistently use this name so it shouldn't be an origin of a problem just a side note
I have a dataset that looks like this:
Valid Example Data
{
type: "step",
label: "Step 1",
fields: [
// An optional field
{
type: "email",
label: "Your Email"
},
// A field that is required and can be either amount|preset
{
type: "amount",
label: "Amount"
},
// A field that is required and can be either credit_card|ach
{
type: "credit_card",
label: "Credit Card"
}
]
}
The fields array can contain many objects of various types. The above example would be valid.
Invalid Example Data
{
type: "step",
label: "Step 1",
fields: [
{
type: "email",
label: "Your Email"
},
{
type: "credit_card",
label: "Credit Card"
}
]
}
This should error as it does not include an object of type amount or presets
Validation Rules
In order to be valid, fields needs to contain 2 objects.
1 of them must be of either { type: "amount" } or { type: "presets" }
1 of them must be of either { type: "credit_card" } or { type: "ach" }
Any combination of the 2 would make fields be valid.
JSON Schema
Here is my (failing) JSON Schema:
{
"title": "step",
"type": "object",
"properties": {
"type": {
"title": "type",
"type": "string"
},
"label": {
"title": "label",
"type": "string"
},
"fields": {
"title": "fields",
"description": "Array of fields",
"type": "array",
"additionalItems": true,
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{ "properties": { "type": { "enum": ["amount", "preset"] } } },
{ "properties": { "type": { "enum": ["credit_card", "ach"] } } }
],
"properties": {
"type": {
"type": "string",
}
}
},
}
},
"required": ["type", "label", "fields"]
}
Here is the JSON Schema Validation Reference
I think between contains, anyOf, allOf, oneOf, and enum I should be able to do this?
Put the following in your /properties/fields schema. That expresses the constraints you need. Remove /properties/fields/items/anyOf (it's wrong) and /properties/fields/additionalItems (it doesn't do anything).
"allOf": [
{
"contains": {
"properties": { "type": { "enum": ["amount", "presets"] } }
}
},
{
"contains": {
"properties": { "type": { "enum": ["credit_card", "ach"] } }
}
}
]