Sitemap

API Contract Testing with JSON Schema in Robot Framework

3 min read5 days ago

--

Catch silent API changes before they reach production, with one reusable keyword

Press enter or click to view image in full size

Most API tests check the status code and a few fields. That catches loud failures. It misses the quiet ones: a field that changes from a number to a string, a field that disappears, or a new null where your app expects a value. These changes pass a basic test and then break the UI or another service.

Get Rudra Surti’s stories in your inbox

Join Medium for free to get updates from this writer.

Contract testing fixes this. You describe the shape of the response once, as a JSON Schema, and every test checks the full response against it. In this article I show how I do it in Robot Framework, using code from my open-source project Robot-Framework-API-Automation.

1. Add one library

You only need the jsonschema Python package next to RequestsLibrary:

robotframework>=7.0
robotframework-requests>=0.9.7
jsonschema>=4.0

2. Write the schema

Keep schemas in a schemas/ folder, one file per response. Mark the fields that must exist as required, and give every field its type:

{
"type": "object",
"required": ["firstname", "lastname", "totalprice", "depositpaid", "bookingdates"],
"properties": {
"firstname": {"type": "string"},
"lastname": {"type": "string"},
"totalprice": {"type": "integer"},
"depositpaid": {"type": "boolean"},
"bookingdates": {
"type": "object",
"required": ["checkin", "checkout"],
"properties": {
"checkin": {"type": "string", "format": "date"},
"checkout": {"type": "string", "format": "date"}
}
}
}
}

3. One reusable keyword

This keyword loads a schema file and validates any response body against it. If anything does not match, the test fails with a clear message that names the field.

*** Settings ***
Library RequestsLibrary
Library OperatingSystem
*** Keywords ***
Response Should Match Schema
[Arguments] ${body} ${schema_file}
${path}= Normalize Path ${CURDIR}/../schemas/${schema_file}
${schema}= Evaluate json.load(open($path)) modules=json
Evaluate jsonschema.validate(instance=$body, schema=$schema) modules=jsonschema

Tip: Normalize Path comes from the OperatingSystem library. If you forget to import it, the dry run fails with "No keyword with name 'Normalize Path'".

4. Use it in tests

*** Test Cases ***
Get Booking Matches Contract
[Tags] contract
${id}= Create Booking
${resp}= GET On Session api /booking/${id}
Response Should Match Schema ${resp.json()} booking.json

The test now reads like a sentence, and it checks every field and type in one line.

5. Add data-driven cases

Robot Framework’s Test Template lets one keyword run many input rows. I use it to send several booking variations and check that each response still matches the contract:

*** Settings ***
Test Template Booking Should Follow Contract
*** Test Cases ***              FIRST      LAST     PRICE    DEPOSIT
Standard booking Rudra Surti 150 True
No deposit Asha Patel 90 False
Zero price Dev Shah 0 True

6. Run it in CI

Tag the tests contract so you can run them alone with robot --include contract tests/. In my project, GitHub Actions runs all 21 tests on every push and uploads the HTML report.

What I learned

  • Keep schemas small and inline. Shared $ref files add setup work for little gain in a test project.
  • Check types, not only presence. Most real bugs I find are a number that became a string.
  • Run contract tests early in the pipeline. They are fast and catch breaking changes before the slower UI tests.

I use Claude to draft schemas from sample responses, then I review every field by hand. It saves time, but the review is what makes the contract right.

The full code is on GitHub: Robot-Framework-API-Automation. More about my work: rudrasurti.github.io.

--

--

Rudra Surti
Rudra Surti

Written by Rudra Surti

Senior SDET | Robot Framework, API & AI-powered test automation with Claude | Selenium · Playwright · Appium | rudrasurti.github.io