Swagger Dredd testing lets you validate your API’s implementation against its OpenAPI (Swagger) specification, ensuring the code actually does what the documentation says it does.
Here’s Dredd running against a local API:
dredd http://localhost:3000/api --spec-files ./swagger.yaml
It’ll then hit your API with requests defined in swagger.yaml and report any discrepancies.
Dredd is fundamentally a contract testing tool. The OpenAPI spec is the contract. Dredd verifies that the server (the implementation) upholds its end of that contract by responding to requests exactly as the spec dictates. This catches bugs that unit tests or end-to-end tests might miss because they’re focused on specific scenarios rather than the whole API surface defined in the spec.
The magic happens in how Dredd interprets the OpenAPI document. It parses the paths, operations (GET, POST, etc.), parameters, request bodies, and expected responses, including their schemas and status codes. For each defined endpoint and method, Dredd constructs a request, sends it to your running API, and then meticulously compares the actual response from your server against the expected response defined in the OpenAPI spec. This comparison is deep: it checks status codes, headers, and crucially, the structure and data types of the response body against the JSON Schema defined in the spec.
Here’s a snippet of an swagger.yaml that Dredd would parse:
openapi: 3.0.0
info:
title: My API
version: 1.0.0
paths:
/users:
get:
summary: Get a list of users
responses:
'200':
description: A list of users
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
When Dredd sees this, it knows to make a GET request to /users. If the server responds with a 200 OK and a JSON array where each item has an id (integer) and name (string), Dredd marks it as passing. If the id is a string, or if it returns a 201 Created instead of 200 OK, Dredd flags it as an error.
You control Dredd’s behavior through command-line arguments and configuration files. The --spec-files flag points to your OpenAPI document(s). --host specifies the base URL of your API. You can also use --require to load custom hooks, which are JavaScript or Ruby scripts that let you manipulate requests and responses, or perform setup/teardown tasks. For example, a hook could generate dynamic test data or assert specific side effects.
The most surprising thing about Dredd is how it forces you to think about your API as a formal agreement rather than just a collection of endpoints. It doesn’t care about your business logic or happy paths in the way traditional tests do; it cares about adherence to the schema and contract. This means you’ll often find yourself fixing your OpenAPI spec first if Dredd complains, because the spec was wrong, not necessarily the code.
Dredd operates by sending raw HTTP requests to your API. It doesn’t understand your application’s framework (e.g., Express, Spring Boot, Django) directly. Instead, it communicates via HTTP. When it receives a response, it parses the Content-Type and, if it’s JSON, deserializes the body to validate it against the defined JSON Schema. For other content types, it performs structural validation based on the schema if available, or simply checks for the presence of expected headers and status codes.
A key aspect many people overlook is how Dredd handles different response types within a single operation. An OpenAPI spec can define multiple possible responses for a given HTTP method (e.g., a 200 OK, a 400 Bad Request, a 404 Not Found). Dredd will generate requests designed to elicit each of these defined responses and validate them independently. This means if you have a POST endpoint that can return a 201 Created on success and a 400 Bad Request with a specific error schema on validation failure, Dredd will test both scenarios by sending appropriate data and then invalid data.
The next hurdle you’ll likely encounter is managing Dredd for multiple API versions or complex OpenAPI documents, often involving multiple files and $refs.