2

What I want to do either via AJV - JSON Schema validation or Custom Keywords (preferably I would go with this): The Array can have 1 or 2 JSON objects with type as 'admin' and 'guest'. The "type":"guest" object will always be there and "type":"admin" object is optional.

Extra Notes:

-The object itself may contain addition attributes and nested objects, in future

-The other valid enums aresuperadmin, admin,user and guest

-The type sequence in array is: superadmin, admin,user and guest. Is it possible to check the sequence? (although its optional)

-The 'guest' type object will always be there and there will be a unique type of object. If any re-occurence any object type (e.g. superadmin, admin,user and guest) then its an error

//Here is the schema:

{
"type": "object",
"properties": {
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "type": { "enum": ["guest", "admin"]
    },
    "rights": {"type": "string"},
    "hyperLink": {"type": "string", "format": "uri"}
    }
  }
  }
}

I need to add 'checkTypeAndValue' flag somewhere in the json so that I can grab the complete JSON object and the corresponding attributes to do a programmatic check?

const checkTypeAndValue = function (schema, completeJSONObj) {
 //
};

ajv.addKeyword('checkTypeAndValue', {
  validate: checkTypeAndValue,
  errors: true
});

and here are some valid and invalid examples:

/Valid 1: As type is 'admin' and so 'rights' SHOULD NOT be in 'guest' object
{
  [
    {
      "type":"admin",
      "hyperLink": "http://www.someguest.com",
      "rights":"all"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com"
    }
  ]
}

//Valid 2: You can have a SINGLE 'guest' object. 'admin' object is not required all the time
{
  [
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com",
      "rights": "limited" //MANDATORY or REQUIRED Attribute
    }
  ]
}

//InValid
{
  [
    {
      "type":"admin",
      "hyperLink": "http://www.someguest.com",
      "rights":"all"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.someadmin.com",
      "rights":"limited"
      //Error ==> As rights=all is there in 1st object, you cannot set 'rights' to any value including blank even having 'rights' attribute is not valid.
    }
  ]
}

Here is the if else condition that I need to sort out:

//Assuming admin object exist with rights....
if( type == admin && rights != ""){
  if(type == guest && rights attribute is there && rights != ""){
    //The 'guest' object will always be there....
    //error: guest 'rights' cannot have a value if type is 'admin' and rights is 'all' or any other value.
  }
}else{
   //Assuming mandatory guest object exist with rights....
   if(guest.rights does not exist OR guest.rights == "")
    //Error: 'rights' is MANDATORY attribute in guest block and error if its empty
   else 
    //Everything is fine
}

Also is there any way by which we can check in an array that there will be only one pair of object of certain type? For example: only one 'guest, 'admin' type. Error, if there are more than one type of 'guest' or 'admin'

//Complete example

{
  [
    {
      "type":"superadmin",
      "hyperLink": "http://www.superadmin.com"      
    },
    {
      "type":"admin",
      "hyperLink": "http://www.admin.com",
      "rights":"all"
    },
    {
      "type":"user",
      "hyperLink": "http://www.user.com"
    },
    {
      "type":"guest",
      "hyperLink": "http://www.guest.com"
    }
  ]
}
11
  • I think this is possible with pure JSON Schema alone. Just to clairfy, will your array only ever have two objects, or is it possible they may have more than 2? Is the order known or unknown (not a problem, but solution may be different)? Commented Sep 27, 2019 at 14:12
  • Actually, it doesn't make a difference. Got a solution for you. Commented Sep 27, 2019 at 14:24
  • The array can have more objects as updated in question. If we can manage the order than it would be fine. As you mentioned this could be tricky, would it be a way by which ajv custom validation can help? Thanks for replying Commented Sep 27, 2019 at 14:39
  • Ah so, if there's an admin, then NO other type may have rights? Commented Sep 27, 2019 at 14:40
  • well the relation is between 'admin' type and 'guest' type at this moment. I don't know whether any change in this relation in future. How about going custom ajv validation to accommodate any near future schema changes for such complexity Commented Sep 27, 2019 at 14:43

1 Answer 1

2

It may seem a little tricky to do this with JSON Schema, but it is possible.

You need to be able conditionally check a negative condition.

So, you'll need to use a combination of if and then, with not.

First the condition: if there's an admin user. Using if, we can then conditionally apply the further checking rule.

Next, the check: guest user cannot have rights.

then is applied when if passes validation. We then need to negate a check that a guest has rights, using not.

You can see this correctly failing validation with the example expected invalid JSON data you provided using https://jsonschema.dev (link is pre-loaded with this schema and your provided instance data. It uses AJV in browser btw.)


Update: I've updated the schema to meet your additional requirements. I've also updated the demo link above.

The schema now only allows admin to have rights if admin is present, and no other user type may have rights if admin is present. Also one item in the array must have rights (as you required).

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "array",
  "if": {
    "contains": {
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "admin"
        }
      }
    }
  },
  "then": {
    "not": {
      "contains": {
        "required": [
          "type",
          "rights"
        ],
        "properties": {
          "type": {
            "not": {
              "const": "admin"
            }
          }
        }
      }
    }
  },
  "contains": {
    "type": "object",
    "required": ["rights"]
  },
  "items": {
    "type": "object",
    "properties": {
      "type": {
        "enum": [
          "guest",
          "admin"
        ]
      },
      "rights": {
        "type": "string"
      },
      "hyperLink": {
        "type": "string",
        "format": "uri"
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

7 Comments

How to get it work for the updated schema where we have 2 additional attributes and the "items" as array key with multiple one enums type as an object.In addition to this, the "rights" is mandatory attribute. Please see the updated schema in the question.
I've updated the answer. Now if admin is present, no other user may have rights, and at least one item in the array must have rights.
Thanks for adding clarity on this issue. However, now I have a final updated schema and I tried to use your approach but eventually it is not working may be because of change in schema. I know I am asking a-lot, but can some-one help? I have updated details under [09/29]************* in the question. Thanks
It's considered bad form to keep changing your question. It turns into a different question because the first part was answered. If you have another more complex question, it's best to ask another question. The additions you've made are very different to your original question.
Question updated to original form to intact the relevancy of solution.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.