Q36 of 40 · Karate
Compare Karate's match DSL to JSON Schema. Which is better for what?
KarateSeniorkaratejson-schemacontract-testingmatchcomparison
Short answer
Short answer: Karate's match is concise and co-located with the test — ideal for fast iteration on API-specific contracts. JSON Schema is verbose but portable: the same file validates in Postman, REST Assured, and any schema validator. Use Karate match for co-located API tests; JSON Schema when the contract is published for consumers across multiple tools or teams.
Detail
Karate's match DSL:
* match response == {
id: '#uuid',
name: '#string',
age: '#? _ >= 0 && _ <= 150',
tags: '#[] #string',
status: '#regex (ACTIVE|INACTIVE)'
}
Advantages:
- One line per field — extremely concise
- Inline with the test — no external file to maintain
- Rich predicates:
#? _ > 0, array markers#[], regex - No tooling setup — just write it in the feature file
Limitations:
- Only works in Karate — you can't share this definition with Postman, REST Assured, or OpenAPI tools
- No support for JSON Schema standard keywords (allOf, oneOf, $ref, format)
- Schema definition is per-test, not a single source of truth
JSON Schema:
{
"type": "object",
"required": ["id", "name", "status"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"name": { "type": "string", "minLength": 1 },
"age": { "type": "integer", "minimum": 0, "maximum": 150 },
"tags": { "type": "array", "items": { "type": "string" } }
},
"additionalProperties": false
}
Advantages:
- Portable: used in Postman, REST Assured, AJV (JavaScript), any conformant validator
- Single source of truth for the contract
additionalProperties: falsestrictly prevents unintended fields- Integrates with OpenAPI spec generation tools
Rule of thumb: use Karate match for developer-facing API tests with fast iteration; use JSON Schema when the contract is a team/cross-service artifact.
// EXAMPLE
schema-comparison.feature
Feature: Karate match vs JSON Schema comparison
Scenario: Using Karate's inline schema (no external file)
* url 'https://api.example.com'
Given path '/users/1'
When method GET
Then status 200
# Inline — fast to write, easy to update, only works in Karate
* match response == {
id: '#uuid',
name: '#string',
email: '#regex .+@.+',
age: '#? _ >= 18',
roles: '#[] #string',
active: '#boolean',
createdAt: '#string'
}
Scenario: Using JSON Schema file (portable contract)
* url 'https://api.example.com'
Given path '/users/1'
When method GET
Then status 200
# Read schema from file — same schema used in REST Assured and Postman
* def schema = read('classpath:schemas/user-schema.json')
* match response == '#(schema)'
# Note: Karate uses '#(^schemaVar)' for schema-reference matching
# where the schema variable contains type markers or nested schemas// WHAT INTERVIEWERS LOOK FOR
Concrete articulation of portability as JSON Schema's primary advantage, Karate's conciseness and co-location as its advantage, and the rule of thumb for choosing. Knowing '#(^schema)' syntax for Karate schema references is a depth signal.
// COMMON PITFALL
Saying 'use Karate match for everything because it's simpler'. When the API contract is a shared team artefact consumed by multiple tools, Karate match is the wrong choice — portability trumps conciseness.