skip to content

A team wants their Karate feature file to validate a response against their published JSON Schema document. What does Karate actually provide for that?

level: seniorimportance: should knowfreq 44%

answer

  1. there is no validator to reach for
  2. the expected payload is the schema
  3. markers evaluated during the walk
  4. def a shape, match against it
  5. schema by example, not by document

basics

~20 s

Karate ships no JSON-Schema validator and no XSD or DTD matcher. Its whole schema story is schema by example: you def an expected payload made of marker strings and match the response against it, checking shape and content in one step.

solid answer

~50 s

There is no schema-document support to reach for. Karate has no JSON-Schema validator, no XSD matcher and no DTD matcher; nothing in the tool reads a schema file and validates against it. What it offers instead is **schema by example**: you build an expected payload out of `#`-marker strings, `def` it as an ordinary variable, and `match` the response against it. `* def catSchema = { id: '#uuid', name: '#string', age: '#number' }` then `* match response == catSchema`, or `* match response.cats == '#[] catSchema'` to apply the same shape to every element of an array. Reuse comes from variables — a shape can be defined in a shared file, `read` in, and nested inside a larger shape. If you genuinely must validate against a schema document, you would have to call a third-party library yourself through Karate's Java interop; that is your dependency and your code, not a Karate feature.

code

gherkin · 18 lines
gherkin
# the 'schema' is an ordinary variable
* def warehouseLocation = { latitude: '#number', longitude: '#number' }
* def productStructure =
"""
{
  id: '#number',
  name: '#string',
  tags: '#[] #string',
  dimensions: { length: '#number', width: '#number', height: '#number' },
  warehouseLocation: '##object'
}
"""

# one product
* match response == productStructure

# a whole array of them
* match response == '#[] productStructure'

go deeper

for a junior

Remember the shape is just a variable holding JSON with marker strings in it, defined with def and used on the right of a match like any other value.

for a middle

Explain that markers are evaluated in place as the payload is walked, so there is no separate schema phase and no schema format to learn.

for a senior

Know the boundary: this is excellent inside your own suite and is not a published contract, so a schema document that external consumers depend on is a real requirement Karate does not meet.

for a principal

Decide whether structural truth lives in a published schema or in the tests, because keeping both and syncing them by hand is the arrangement that reliably rots.

## The honest answer first Karate does not do JSON-Schema validation. There is no validator, no `matchesSchema`-style step, no XSD support and no DTD matcher anywhere in the tool. If a candidate tells you Karate "validates the response against a JSON Schema", they are describing a different tool. This is worth stating flatly, because the assumption is common among people arriving from HTTP-assertion libraries where schema-document validation is a first-class matcher. The XML side is the same. XML payloads are parsed and can be matched with XPath on the left and markers on the right, but nothing validates a document against a grammar. Where a `DOCTYPE` is handled at all, the behaviour is to **discard** it during parsing, not to validate against it. ## What replaces it: schema by example Karate's model is that a schema *is* an expected payload, written in the same JSON you would write for an exact match, with marker strings where the value is unpredictable: ```gherkin * def catSchema = { id: '#uuid', name: '#string', age: '#number', tags: '#[] #string', owner: '##object' } * match response == catSchema ``` There is no separate validation phase. Markers are evaluated in place as the match engine walks the payload, which has three consequences worth understanding: 1. **Shape and content are asserted together.** `{ status: 'ACTIVE', id: '#uuid' }` pins one field to a literal and another to a type in the same object. A schema document cannot express "and this particular value must be `ACTIVE` for this test" without a second assertion. 2. **The strictness of the surrounding match still applies.** Under `==`, a key the response returns but the shape does not name fails the step. The shape is not just a lower bound on the payload. 3. **Composition is variable composition.** A shape refers to another shape by name, so nesting and array reuse are the same mechanism, not schema-specific features like `$ref`. ## Getting reuse without a schema registry Everything a schema file would give you comes from ordinary Karate plumbing: - **Define once, use everywhere** — `def` the shape in a common feature or a `.json` file and `read` it in, then reference the variable from any assertion. - **Nest shapes** — a value inside one shape can be another shape's variable, to any depth. - **Apply per element** — `'#[] catSchema'` matches every element of an array against the shape, and `'##[] catSchema'` does the same while allowing the array itself to be `null`, or the key to be missing when the marker sits inside an expected object. Against a path it is stricter than it looks: `match response.cats == '##[] catSchema'` with no `cats` in the payload still fails with `actual is not an array`, because a missing path degrades to `#notpresent` rather than `null`. - **Relax a field deliberately** — `'##string'` for a key that may be stripped, `'#ignore'` for one you cannot constrain at all. The result reads as one artefact rather than two: no schema file that drifts from the tests that were supposed to enforce it. ## What you give up, and what you gain | | schema document | schema by example | |---|---|---| | where it lives | a separate file, its own format | a variable in the test language | | what it can say | structure and types | structure, types **and** exact values | | publishing to others | designed for it | not a deliverable | | formal grammar features | mature | none | The trade is real. A published schema is a contract other teams can consume, and Karate's shapes are not — they are test fixtures. If the schema document is the source of truth for consumers outside your suite, validating against it is a genuine requirement, and Karate does not meet it. You would be calling a third-party validator through Java interop, owning that dependency and that glue yourself. ## What to say in an interview State the denial plainly, then show the model: `def` a shape of markers, `match` against it, `'#[] shape'` for arrays, `##` for optional keys, shapes referring to shapes for composition. The follow-up an interviewer is usually looking for is whether you know the boundary — that this covers structural assertions inside your own suite very economically, and does not replace a schema document that other teams consume. ## Keeping a shape in a file Because the shape is just JSON, the closest thing to a schema file is a `.json` file read into a variable: ```gherkin * def catSchema = read('classpath:schemas/cat.json') * match response == catSchema * match response.litter == '#[] catSchema' ``` The file contains marker strings where a schema would carry type declarations, and referencing it is an ordinary variable reference — so nesting one shape inside another, or applying it per array element, needs no extra machinery. A shape can equally be produced by a feature you `call`, which is the usual way a suite shares several related shapes from one place. ## Reading a structural failure A failing shape does not report "does not conform". The match report descends to the offending node and prints the path, the validator's own message and both values, for example `$.cats[0].id | not a string`. That is generally more useful than a schema validator's output for this purpose, because it points at one key in one element rather than listing every rule that did not hold, and because the same report format covers exact-value mismatches in the same payload.

  • Where would you keep a Karate shape that several feature files need?
    In a file that is `read` in — either a `.json` holding the marker object, or a feature you `call` that returns shapes as variables. Referencing it is then a normal variable reference, so nesting and array reuse work unchanged. Keep it near the suite rather than treating it as a published artefact: it is a test fixture with no consumers outside your tests, and pretending otherwise is how it drifts.
  • What can a shape built from markers assert that a schema document cannot?
    Exact values, mixed into the same object as the type checks — `{ status: 'ACTIVE', id: '#uuid' }` pins one field literally and one by shape in a single step. It also inherits the strictness of the surrounding match, so under `==` a key the response returns but the shape does not name fails the assertion, which most schema documents treat as permitted unless explicitly forbidden.

saying these in an interview costs you the question

  • Claims Karate validates responses against a JSON Schema file
  • Says there is a built-in XSD or DTD matcher for XML
  • Thinks markers are checked in a separate pass before assertions
  • Treats a marker shape as a contract other teams can consume
  • Assumes reuse needs a schema registry rather than a variable
  • Believes a shape can only assert types, never exact values