If contract testing is one approach to "the API contract," OpenAPI is the other. Where Pact captures the consumer's needs, OpenAPI captures the provider's declared API: every endpoint, every parameter, every response shape, written down in a machine-readable file that both humans and tools can use. As a QA engineer, an OpenAPI spec is one of the most useful artefacts you can have access to — it lets you generate tests, validate responses, mock servers, and detect breaking changes automatically. This lesson explains the format and the ecosystem around it.
OpenAPI vs Swagger — same thing, different names
Both names refer to the same standard.
- Swagger was the original name, created in 2011 by Smartbear. It included a spec format, a UI, and code generators.
- In 2015 the spec was renamed OpenAPI and donated to the Linux Foundation. The Swagger brand now refers to the tooling (Swagger Editor, Swagger UI, Swagger Codegen), while OpenAPI Specification (OAS) refers to the format itself.
In practice you'll hear both names used interchangeably. When someone says "the swagger doc" they mean the OpenAPI spec file.
What the spec looks like
An OpenAPI document is a YAML or JSON file describing your API. A minimal slice for GET /users and POST /users:
openapi: 3.0.0
info:
title: User Service
version: 1.2.0
paths:
/users:
get:
summary: List all users
parameters:
- name: role
in: query
schema:
type: string
enum: [admin, editor, viewer]
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
responses:
"200":
description: List of users
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/User"
post:
summary: Create a user
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UserInput"
responses:
"201":
description: Created
"409":
description: Email already exists
components:
schemas:
User:
type: object
required: [id, name, email]
properties:
id: { type: integer }
name: { type: string }
email: { type: string, format: email }
role: { type: string, enum: [admin, editor, viewer] }Read it top to bottom: the title and version describe the API as a whole; paths enumerates each URL; each path lists the verbs supported, with parameters, request body, and possible responses; components.schemas defines reusable types referenced via $ref.
That single file is simultaneously documentation, schema definition, and test contract.
The OpenAPI ecosystem
Once your API has a spec, an entire toolchain becomes available:
- – Interactive docs
- – Try it out
- – Hosted at /docs
- – Client SDKs
- – Server stubs
- – Multiple languages
- – Prism (Stoplight)
- – Mock examples
- – Faster local dev
- Schemathesis –
- Dredd –
- Postman import –
- ajv –
- openapi-validator –
- Spec-vs-runtime checks –
Each branch is something you, as a tester, can lean on without writing it from scratch.
Swagger UI — the docs experience
Most teams host their OpenAPI spec at a known URL — typical paths are /api-docs, /swagger-ui, /openapi.yaml, or /openapi.json. Visit it in a browser and you usually get Swagger UI: an interactive page that lets you expand each endpoint, see parameters, and try requests with real auth.
For a tester, Swagger UI is the fastest way to:
- Understand what endpoints exist.
- Sanity-check what an endpoint returns for known inputs.
- Generate a curl command from the form (most Swagger UIs have a "copy as curl" button).
- Spot-check that the docs match reality.
Treat it as your first stop on a new API.
Generating tests from the spec
Two tools are worth knowing:
- Schemathesis — Python-based, generates property-based tests from the spec. Hits every endpoint with a wide variety of inputs and validates responses against the schema. Catches surprising bugs in input handling.
schemathesis run https://api.example.com/openapi.json --checks all - Dredd — language-agnostic, runs a fixed set of tests derived from the spec's examples. Less aggressive than Schemathesis but easier to integrate.
dredd openapi.yaml https://api.example.com
Both tools are CI-friendly. The simplest CI step is "run schemathesis against staging — fail if any endpoint fails its own schema." That alone catches a startling fraction of real bugs.
Validating responses against the spec at runtime
In your hand-written tests, you can also validate every response against the spec's schema. Libraries like openapi-core (Python), openapi-validator-middleware (Node), or swagger-request-validator (Java) read the spec and validate live responses.
Pseudocode:
from openapi_core import OpenAPI
spec = OpenAPI.from_file("openapi.yaml")
def assert_matches_spec(response, path, method):
spec.validate_response(path, method, response)Add it to your test fixture and every API call gets a free schema check.
Detecting breaking changes between spec versions
Once the spec is checked into version control, changes to the spec are first-class signals. Tools like openapi-diff compare two versions and flag breaking changes:
- Removed endpoints.
- Renamed fields.
- Tightened type constraints.
- New required fields.
Wire this into a PR check: "if the spec change is breaking, require explicit approval and a deprecation note." That alone catches a lot of accidental breakage.
OpenAPI as documentation source of truth
The most powerful pattern: treat the OpenAPI spec as the single source of truth. Generate everything from it:
- The provider's controller code (or annotations that produce the spec).
- The consumer's client SDKs.
- The docs page.
- The tests.
- The mock server.
When all of those are derived from the same file, the spec can't drift from reality — code generation enforces alignment. Teams that adopt this pattern often eliminate an entire category of "the docs say X but the API does Y" bugs.
Where to find the spec
For a public API:
- The docs site usually has a "Download OpenAPI" link.
- A common URL is
https://api.example.com/openapi.jsonor/swagger.jsonor/v3/api-docs. - Some teams check the spec into the repo as
openapi.yaml.
For an internal API where you can't find the spec:
- Ask the team. The spec might be auto-generated and hosted at an unfamiliar path.
- Look for annotations in the source code (
@OpenAPI,@swagger, FastAPI's auto-generation, Spring'sspringdoc). - If no spec exists, that's a finding — the team might not realise how much testing leverage they're leaving on the table.
⚠️ Common mistakes
- Trusting the spec uncritically. Specs drift. Always validate that endpoints actually exist and behave as documented before relying on the spec for test design.
- Skipping spec-driven test generation. If you have a spec, Schemathesis or Dredd will write hundreds of useful tests for free. Not running them once is a missed opportunity.
- Using example values as the only test inputs. Spec examples are illustrative. Test boundary cases, invalid inputs, and security cases too.
🎯 Practice task
Use a real OpenAPI spec end-to-end. 30 minutes.
- Open the Petstore example — the canonical OpenAPI demo.
- Click around the Swagger UI. Pick one endpoint (
POST /petis good) and identify each section: parameters, request body schema, possible responses. - Download the raw spec from
https://petstore3.swagger.io/api/v3/openapi.json. Skim the JSON. - Find an OpenAPI spec for an API you actually care about — your own product, GitHub, Stripe, or any public API. Confirm the URL.
- Install Schemathesis (
pip install schemathesis) and run it against an endpoint:schemathesis run https://petstore3.swagger.io/api/v3/openapi.json -E "/pet". Observe what it tests. - Stretch: find one endpoint where the spec disagrees with reality (a parameter that no longer exists, a response field renamed). Write up the discrepancy as a bug — that's the everyday value of spec-driven testing.
You can now use OpenAPI specs to multiply your testing leverage. The final lesson of this chapter explores what to do when the docs and the API don't agree.