# Test API contracts using Redocly Respect

Use Respect, powered by Arazzo workflows, for API contract testing.

Learn how to:

- Automate repetitive API workflows.
- Add API contract tests to CI/CD routines.
- Keep API documentation synchronized with actual API behavior.
- Share described workflows across teams.
- Use the open-source [Redocly CLI](https://www.npmjs.com/package/@redocly/cli) to execute Arazzo workflows, inspect contract test results, and fix mismatches between the OpenAPI description and the actual API response.


## The problem

Many teams test APIs by writing test code in the same language as the API implementation.
This approach can work well for a single service, but it becomes harder to maintain in systems with multiple products, repositories, and programming languages.

Another common challenge is keeping API documentation aligned with actual API behavior.
Developers may update an endpoint but forget to update its OpenAPI description, or the documentation may change without the implementation following it.
Over time, these small differences make it harder for QA engineers, developers, and technical writers to trust the API contract.

Respect helps address this problem by executing Arazzo workflows against a running API and validating the responses against the connected OpenAPI description.
This strategy makes API contract testing more declarative and easier to share across teams.

## Prerequisites

To follow the examples in this article, you need:

- Basic familiarity with [Arazzo](/learn/arazzo/what-is-arazzo).
- An API described with OpenAPI.
The examples use a modified version of the Redocly Cafe API description.


Tutorial content
The API description used here intentionally contains a discrepancy for demonstration purposes.

## Explore the OpenAPI description

Open `redocly-cafe-api.yaml` in the right panel to follow along.
The two important pieces for this walkthrough are the `GET /menu` operation and the `MenuItemList` response schema it references.

The `GET /menu` operation returns a paginated list of menu items.
The `200` response points to the `MenuItemList` schema, which is where the intentional discrepancy lives.

The schema declares the response as an **array**, but the real API returns a **paginated object** with `object`, `page`, and `items` fields.
Later in this walkthrough, Respect will compare this contract with the real API response and surface the mismatch.

## Create an Arazzo description

There are several ways to create an Arazzo description:

- Read the [Arazzo specification](https://spec.openapis.org/arazzo/latest.html) and write the file from scratch for full control.
- Use the `npx @redocly/cli generate-arazzo openapi.yaml` command as a starting point.
- Use AI assistance to draft the Arazzo description, then lint the output to catch structural or syntax errors.


Whichever approach you choose, validate the Arazzo file with Redocly CLI:


```bash
npx @redocly/cli lint redocly-cafe-api.arazzo.yaml
```

The tool informs you that the description is valid.

Switch to `redocly-cafe-api.arazzo.yaml` in the right panel and walk through it section by section.

`sourceDescriptions` defines the connection to one or more OpenAPI files.

The example references the local `redocly-cafe-api.yaml` and gives it the name `redocly-cafe-api`.
This name is used later to refer to operations from that description.

A single Arazzo file can declare multiple `workflows`.
Each workflow has a unique `workflowId` and a `summary`.
This example defines `menu-items-workflow`, which retrieves the menu items list.

Each workflow is composed of one or more `steps`.
A step is the smallest unit of execution: typically a single API call against an operation from the connected source description.

The step uses `operationId` to connect to an operation in the OpenAPI description, using the pattern:


```text
$sourceDescriptions.<source-name>.<operationId>
```

In this example, the step resolves to the `listMenuItems` operation from the `redocly-cafe-api` source.

This is the operation the step resolves to in `redocly-cafe-api.yaml`.

Because the step is connected to an OpenAPI operation, Respect knows the documented status codes, content types, and response schema for the request and can automatically validate them.

Steps can pass parameters to the operation.
Here, the `limit` query parameter restricts the response to a single menu item, which keeps the example output small and easy to read.

Steps can include a `successCriteria` block to define workflow-specific expectations.

This example asserts that the API responds with a `200` status code.
Respect also runs additional automatic checks based on the connected OpenAPI description (see the next section).

## Execute the workflow with Redocly CLI

[@redocly/cli](https://www.npmjs.com/package/@redocly/cli) is an open-source tool that can execute Arazzo descriptions with the `respect` command:


```bash
npx @redocly/cli respect redocly-cafe-api.arazzo.yaml
```

The workflow targets the server defined in the OpenAPI description, so you do not need to provide one via the command line.

The full output is useful for debugging, but the most important lines are the checks near the end of the step:

- The success criteria check passes because the API returns status code `200`.
- The status code and content type checks pass because the response matches the documented response metadata.
- The schema check **fails** because the response body shape does not match the documented schema.


details
summary
Respect execution output

```bash
    Running workflow redocly-cafe-api.arazzo.yaml / menu-items-workflow 
 
  ✗ GET /menu - step get-products 

    Request URL: http://localhost:4096/menu?limit=1
    Request Headers:
      accept: application/json, application/problem+json 
 

    Response status code: 200
    Response time: 17 ms
    Response Headers:
      access-control-allow-credentials: true
      connection: keep-alive
      content-length: 435
      content-type: application/json; charset=utf-8
      date: Wed, 29 Apr 2026 12:00:44 GMT
      etag: W/"1b3-id35eE7Zv3L2+3iA/a3QCfYtLb0"
      keep-alive: timeout=5
      vary: Origin
      x-powered-by: Express
    Response Size: 435 bytes
    Response Body:
      {
        "object": "list",
        "page": {
          "startCursor": "ixCALWlkOnByZF8wMDAwMDAwMDAwc2VlZHRyYW1zMDAwMDAwMAM",
          "endCursor": "ixCALWlkOnByZF8wMDAwMDAwMDAwc2VlZHRyYW1zMDAwMDAwMAM",
          "hasNextPage": true,
          "hasPrevPage": false,
          "limit": 1,
          "total": 5
        },
        "items": [
          {
            "id": "prd_0000000000seedtrams0000000",
            "name": "tiramisu",
            "price": 13000,
            "category": "dessert",
            "createdAt": "2026-04-29T10:00:50.610Z",
            "updatedAt": "2026-04-29T10:00:50.610Z",
            "object": "menuItem",
            "calories": 450
          }
        ]
      } 
 
    ✓ success criteria check - $statusCode == 200
    ✓ status code check - $statusCode in [200, 400, 500]
    ✓ content-type check
    ✗ schema check 

  Summary for redocly-cafe-api.arazzo.yaml
  
  Workflows: 1 failed, 1 total
  Steps: 1 failed, 1 total
  Checks: 3 passed, 1 failed, 4 total
  Time: 58ms
```

In addition to the success criterion declared in the Arazzo file, Respect performed three additional checks automatically:

- `status code check`
- `content-type check`
- `schema check`


Because the workflow step is connected to an OpenAPI description, [@redocly/cli](https://www.npmjs.com/package/@redocly/cli) verifies that the API returns a documented status code, the expected content type, and a response body that matches the documented schema.

## Understand the schema failure

Switch back to `redocly-cafe-api.yaml` in the right panel.
The failed schema check reports the following message:


```text
| ^^ 👈🏽  type must be array
```

The OpenAPI description declares `MenuItemList` as an **array**, but the actual API response is a paginated **object** with `object`, `page`, and `items` properties.
This is the intentional discrepancy in the example.

Respect made this drift visible immediately, without anyone having to read both the OpenAPI description and the API output side-by-side.

## Fix the schema

In `redocly-cafe-api.yaml`, change `MenuItemList` from an `array` to an `object` with `object`, `page`, and `items` properties so the schema matches the response the API actually returns.

Compare the highlighted block in the right panel with the corrected version below:


```yaml
MenuItemList:
  type: object
  properties:
    object:
      type: string
      const: list
      description: Entity name.
    page:
      $ref: '#/components/schemas/Page'
    items:
      type: array
      items:
        $ref: '#/components/schemas/MenuItem'
  required:
    - object
    - page
    - items
```

Re-run the workflow to confirm that all checks now pass:


```bash
npx @redocly/cli respect redocly-cafe-api.arazzo.yaml
```

After the schema is updated, the response body matches the documented contract.

This example demonstrates the core value of contract testing with Respect: when the API and its OpenAPI description drift apart, the workflow highlights the mismatch immediately.

## Practical applications

After you create and verify an Arazzo workflow locally, you can use it in several ways:

- Include the workflow in a CI/CD pipeline to keep API documentation synchronized with actual API behavior:

```bash
# Spawn your API instance, then run the workflow
npx @redocly/cli respect redocly-cafe-api.arazzo.yaml --verbose
```
- Automate routine API workflows for development and QA tasks.
- Describe important application flows with Arazzo and share them with team members.
Non-technical users can also use visualization tools like Replay to understand the workflows.


## Summary

Arazzo provides a standard way to describe API workflows declaratively.
Respect uses those workflows to run API contract tests against real API behavior.

With this approach, teams can maintain API test coverage, detect documentation drift earlier, and share executable API workflows across engineering, QA, and documentation teams.