Q12 of 40 · Karate

How does Karate handle JSON schema validation differently from REST Assured?

KarateMidkarateschema-validationmatchapi-testingjson-schema

Short answer

Short answer: Karate's # markers (#string, #number, #uuid, #regex, #present, #notnull) do inline structural validation without an external file. REST Assured requires the json-schema-validator dependency and a JSON Schema file on classpath. Karate is faster to write for API-specific tests; JSON Schema is more portable across tools and teams.

Detail

Karate's inline schema — expressed directly in the match assertion:

* match response == {
    id:        '#uuid',
    name:      '#string',
    email:     '#regex .+@.+\..+',
    age:       '#? _ > 0 && _ < 150',
    active:    '#boolean',
    createdAt: '#string',
    role:      '#string',
    tags:      '#[] #string'
  }

This is the entire "schema file" — it lives inline in the feature.

#[] — array schema: '#[] #string' means "array of strings". '#[1] #number' means "array with at least 1 number".

#? — predicate: '#? _ > 0' means "a number greater than 0" — custom JavaScript predicate.

REST Assured's JSON Schema approach: a separate user-schema.json file with full JSON Schema Draft-07 syntax, imported with matchesJsonSchemaInClasspath(). More portable — the same schema file can validate in Postman, any JSON Schema validator, or REST Assured simultaneously.

Trade-off: Karate's inline approach is faster to iterate during development; JSON Schema is better when the contract must be shared with other teams, documented publicly, or validated by multiple tools in the pipeline.

// EXAMPLE

schema-validation.feature

Feature: Response schema validation

  Scenario: User response matches expected schema
    * url 'https://api.example.com'
    * header Authorization = 'Bearer test-token'
    Given path '/users/1'
    When  method GET
    Then  status 200

    # Inline schema — no external file needed
    * match response == {
        id:        '#uuid',
        name:      '#string',
        email:     '#regex .+@.+',
        age:       '#? _ >= 0 && _ <= 150',
        roles:     '#[] #string',
        address: {
          city:    '#string',
          country: '#string'
        },
        createdAt: '#string',
        updatedAt: '#string'
      }

    # For a reusable schema — define it in Background or a shared feature
    * def userSchema = { id: '#uuid', name: '#string', email: '#string' }
    * match response == '#(^userSchema)'    # schema reference

// WHAT INTERVIEWERS LOOK FOR

The # marker vocabulary (#string, #number, #uuid, #regex, #? predicate, #[] array), knowing that this is inline schema validation without an external file, and the honest comparison with JSON Schema — portability vs convenience.

// COMMON PITFALL

Thinking Karate's match can't express complex schemas. The #? predicate, #[] array markers, and nested object matching together cover most real-world schema validation needs without a separate file.