Karate DSL : How to check if the JSON object is optional, but if that object comes the keys inside that object should be of correct schema?

Viewed 1762

I want to validate a JSON schema where an object in a nested JSON response is optional but if the object comes the keys in that object should also come.

Sample Response :-

{
    "id" : "1234",
    "targetPhoneNumber" : "1234",
    "paid" : { //optional
      "units" : "asd", //mandatory if the paid object is coming
      "amount" : 12.00 //mandatory if the paid object is coming
    },
    "date" : "2019",
    "boolean" : false,
    "transactionId" : "1234"
  }

I need schema checks for these cases.

1) If the paid object is coming it should be a JSON object and should contains units as string and amount as mandatory. 2) If the paid object is not coming still the schema validation should pass.

2 Answers

Combining 'self' validation expressions and karate.match(actual, expected) API gives some way to achieve this,

This should work,

* def schema =
"""
{
      "boolean": "#boolean",
      "date": "#string",
      "id": "#string",
      "paid": "##object? karate.match(_,{\"amount\": \"#number\",\"units\": \"#string\"}).pass",
      "targetPhoneNumber": "#string",
      "transactionId": "#string"
}
"""

If you don't want to add your subSchema inline / if your subschema is too large you can try this

* def passSchema =
"""
{
    "amount": "#number",
    "units": "#string"
}
"""
* def schema =
"""
{
    "boolean": "#boolean",
    "date": "#string",
    "id": "#string",
    "paid": "##object? karate.match(_,passSchema).pass",
    "targetPhoneNumber": "#string",
    "transactionId": "#string"
}
"""

Simple JSON schema:

{
      "boolean": "#boolean",
      "date": "#string",
      "id": "#string",
      "paid": "##object? karate.match(_,{\"amount\": \"#number\",\"units\": \"#string\"}).pass",
      "targetPhoneNumber": "#string",
      "transactionId": "#string"
}

It's possible to do this with conditionals:

* def outerMatcher =
"""
{
"id" : "#string",
"targetPhoneNumber" : "#string",
"paid" : "##object",
"date" : "#string",
"boolean" : "#boolean",
"transactionId" : "#string"
}
"""

* def paidMatcher =
"""
{
  "units": "#string",
  "amount": "#number"
}
"""

* def innerMatcher = karate.match(response.paid, "#object").pass ? paidMatcher : "#notpresent"

* match response == outerMatcher
* match response.paid == innerMatcher
Related