Imagine this. Your API returns a JSON object with first name, last name, and age. Your application displays "John Smith, your age is 35." Everything works.
Then one day, developers remove the age property from the response. No one tells you. The app now shows "Your age is undefined." A breaking change slipped right through, and your tests didn't catch it.
JSON Schema testing in Playwright solves this problem. Instead of writing dozens of individual assertions for every property, you validate the entire response structure with a single schema check. Let's dive in.
What Is JSON Schema?
JSON Schema is a JSON object that describes the structure of another JSON object. Think of it as a contract. It defines what properties should be in the response, what types those properties should have, and the overall structure.
Say your API returns this:
{ "firstName": "John", "lastName": "Smith", "age": 35}
The JSON Schema for this response would look like this:
{ "type": "object", "properties": { "firstName": { "type": "string" }, "lastName": { "type": "string" }, "age": { "type": "number" } }, "required": ["firstName", "lastName", "age"]}
The schema says: this response must be an object with three properties. firstName and lastName must be strings. age must be a number. All three are required.
If the API suddenly removes age from the response, the schema validation fails. If age comes back as a string instead of a number, the validation fails. You catch the problem immediately.
Why Not Just Assert Every Property?
You might be thinking, "I can just write an assertion for each property and check if it exists." For a simple object with three properties, sure. But real API responses are not that simple.
Take a typical articles endpoint of Coduit application. The response can easily have 200 lines of JSON with nested objects, arrays, and dozens of properties. Writing individual assertions for all of them? You'd spend more time on assertions than on the actual tests.
JSON Schema handles this much more intelligently. A 200-line response might produce a schema of just 85 lines.
Why? Because schemas understand repetitive structures. If your response contains an array of 10 article objects, each with the same structure, the schema defines that structure once. It knows that articles is an array, each item is an object, and each object has slug (string), title (string), description (string), favoritesCount (number), favorited (boolean), and so on.
One schema. One validation call. Every property checked. Yes, that simple :)
How to Create a JSON Schema
You don't have to write schemas by hand. There are online tools that automatically generate a JSON Schema from a JSON object.
Search for "JSON to JSON Schema converter" and you'll find tools like transform.tools. Paste your API response on the left, get the schema on the right. Copy it, save it as a .json file in your project, and you're ready to validate.
Here's the workflow:
Send a request to your API (using Postman, curl, or Playwright itself)
Copy the response body
Paste it into a JSON-to-JSON-Schema converter
Review the generated schema, check that types and required fields make sense
Save the schema as a file in your test project (e.g.,
schemas/tags.schema.json)
TIP Always review the generated schema before using it. The converter does a good job, but you may want to adjust which properties are
requiredand which are optional based on your API's actual contract.
Setting Up JSON Schema Validation in Playwright
Playwright doesn't have built-in JSON Schema validation, so you need a validation library. The most popular choice is Ajv (Another JSON Schema Validator). It's fast, well-maintained, and supports all JSON Schema drafts.
Install it:
npm install ajv --save-dev
Then create a helper function that you can reuse across all your tests:
import Ajv from "ajv";const ajv = new Ajv();export function validateJsonSchema(data: object, schema: object) { const validate = ajv.compile(schema); const isValid = validate(data); return { isValid, errors: validate.errors };}
That's it. Three lines of real logic. This function takes your API response data and a schema, runs the validation, and returns whether it passed along with any errors.
JSON Schema Testing in Playwright: Simple Example
Let's start with something simple. Say you have a tags endpoint that returns:
{ "tags": ["coding", "testing", "playwright"]}
First, generate the schema. Based on this response, the schema looks like this:
{ "type": "object", "properties": { "tags": { "type": "array", "items": { "type": "string" } } }, "required": ["tags"]}
Save it as schemas/tags.schema.json. Now write the Playwright test:
import { test, expect } from "@playwright/test";import { validateJsonSchema } from "../utils/validateJsonSchema";import tagsSchema from "../schemas/tags.schema.json";test("tags response matches JSON schema", async ({ request }) => { const response = await request.get("/api/tags"); const body = await response.json(); const { isValid, errors } = validateJsonSchema(body, tagsSchema); expect(isValid, `Schema errors: ${JSON.stringify(errors)}`).toBe(true);});
Notice that we use the Playwright built-in request fixture, passed as an argument to the test. This fixture gives us access to API request methods without launching a browser.
What does this test catch?
If
tagsreturns numbers instead of strings, the validation failsIf
tagsreturns an object instead of an array, the validation failsIf the
tagsproperty is missing entirely, the validation failsIf the property name changes from
tagstotag, the validation fails
One test, four safety checks. No brainer at all!
JSON Schema Testing in Playwright: Complex Example
Now let's look at something more realistic. An articles endpoint that returns a response with 200+ lines:
{ "articles": [ { "slug": "how-to-test-apis", "title": "How to Test APIs", "description": "A guide to API testing", "body": "Full article content...", "tagList": ["testing", "api"], "favorited": false, "favoritesCount": 12, "author": { "username": "artem", "bio": "QA Engineer", "image": "https://example.com/photo.jpg", "following": false } } ], "articlesCount": 1}
The generated schema handles all of this, including the nested author object and the tagList array. Even though the actual response may contain 10 or 20 articles, the schema only defines the structure once. Every article follows the same pattern, so one definition covers them all.
import { test, expect } from "@playwright/test";import { validateJsonSchema } from "../utils/validateJsonSchema";import articlesSchema from "../schemas/articles.schema.json";test("articles response matches JSON schema", async ({ request }) => { const response = await request.get("/api/articles"); const body = await response.json(); const { isValid, errors } = validateJsonSchema(body, articlesSchema); expect(isValid, `Schema errors: ${JSON.stringify(errors)}`).toBe(true);});
The test looks almost identical to the simple one. That's the point. Whether your response has 3 properties or 300, the test code doesn't change.
Required vs Optional Properties
Not every property in your schema needs to be required. If a property is optional in your API (for example, a user's bio field might not always be present), remove it from the required array in the schema.
When a property is required, and it's missing from the response, the schema validation fails. When a property is not required, and it's missing, the validation passes.
This way, you define the contract based on what your API actually guarantees, not what it happens to return in one specific response.
JSON Schema and Contract Testing
You might have heard about contract testing. There are two types: consumer-driven contracts and provider-driven contracts.
When you validate your API response against a JSON Schema, you are doing provider-driven contract testing. The API is your provider. The schema is your contract. The contract defines what the provider is expected to return.
By running schema validation tests, you catch integration issues early. If the API team changes the response structure, your tests fail immediately, before the change reaches production and causes "undefined" values in your application.
This works especially well for teams where frontend and backend are developed separately. The JSON Schema becomes the shared agreement between the two sides. If either side breaks the contract, tests catch it.
If you want to go deeper into API testing with Playwright, including CRUD operations and advanced patterns, check out the linked article.
Best Practices for JSON Schema Testing
Keep schema files in a dedicated schemas/ folder in your project. Version them alongside your tests so you always know which schema version goes with which API version.
When the API changes intentionally, regenerate your schemas. The goal is to catch unintentional changes, not to block planned updates.
Schema validation checks the structure. Functional tests check values and logic. Use both. Validate the schema first, then assert on specific values that matter for your test scenario. Together, they give you full coverage.
When validation fails, Ajv provides detailed error messages that tell you exactly which property failed and why. Pass those errors into your assertion message so they show up in the test report. Trust me, you'll thank yourself when debugging at 11pm.
Final Thoughts
JSON Schema testing in Playwright takes about 10 minutes to set up. After that, you validate entire API response structures in a single call instead of writing assertions for every property. Breaking changes get caught before they hit production. And you get provider-driven contract testing without any complex infrastructure.
Pick one of your API responses, convert it to a schema using an online tool, set up Ajv, and write your first validation test. Once you see how little code it takes, you'll want to add it everywhere.
Playwright is growing in popularity on the market very quickly and is becoming the go-to framework for both UI and API test automation. Get the new skills at Bondar Academy with the Playwright API Testing Mastery program. Start from scratch and become an expert to increase your value on the market!
Frequently Asked Questions
Does Playwright have built-in JSON Schema validation?
No. You need an external library like Ajv or Zod. Ajv is the most popular choice because it supports all JSON Schema drafts and gives you detailed error messages when validation fails.
What is the difference between Ajv and Zod for schema validation?
Ajv validates against standard JSON Schema files (plain JSON). Zod lets you define schemas directly in TypeScript code. If your team already has JSON Schema files from the API docs, go with Ajv. If you prefer a TypeScript-first approach, Zod is a solid option.
How do I generate a JSON Schema from an API response?
Use an online converter like transform.tools. Paste your JSON response, and it generates the schema automatically. You can also use libraries like genson-js to generate schemas programmatically in your test setup.
Should I validate the JSON Schema on every API test?
Not necessarily. Create dedicated schema validation tests that run as part of your suite. Your functional tests can focus on specific values, while schema tests guard the overall structure.
What is provider-driven contract testing?
Provider-driven contract testing validates that the API (the provider) returns responses matching a predefined contract (the schema). When you validate API responses against a JSON Schema in your Playwright tests, that's exactly what you're doing. It catches breaking changes before they reach production.
Can I use JSON Schema validation with Playwright's UI tests?
Yes. If your UI tests intercept network requests or make API calls alongside UI interactions, you can validate the intercepted responses against a schema. This is a good way to catch API-level issues during end-to-end testing.
