Docs
API Contract Testing

API Contract Testing

Optic tests that the runtime behavior of an API matches what is documented in its OpenAPI spec. optic capture uses traffic from integration tests, end-to-end tests or manually crafted requests to test the accuracy of your documentation.

Run optic capture openapi.yml to verify traffic against your OpenAPI spec, and run optic capture openapi.yml --update to update your spec when it does not match the traffic.

If you haven't installed the Optic CLI yet, install it now.

npm install -g @useoptic/optic

Setup capture configuration

💡

You can clone our example repo to try out optic capture against a repo that is already set up.

git clone git@github.com:opticdev/examples.git
cd ./examples/apps/bookstore-api
npm install

Once you've set up the repo, you can run optic capture openapi.yml to verify traffic against your OpenAPI spec, and optic capture openapi.yml --update=interactive to update any diffs.

To start capturing your test traffic, run:

optic capture init /path/to/openapi.yml

This will generate an example configuration that you will need to edit for your tests and server. You will need to specify:

  • A command to run your server (server.command)
    • you can omit this if the server is already running (e.g. against a remote server) or is started separately
  • the URL where your server can be reached (server.url) (e.g. http://localhost:3000 or https://api.example.com)
  • A command to run your tests (requests.run)
    • Your tests must make requests through the http layer (Optic captures network traffic and uses a reverse proxy to capture these requests)
    • You will also need to update your test script to send requests to Optic's reverse proxy, this will be available in the environment variable OPTIC_PROXY
optic.yml
capture:
  openapi.yml:
    server:
      command: your-server-command
      # The url where your server can be reached once running.
      url: http://localhost:8080
      # A readiness endpoint for Optic to validate before sending requests.
      ready_endpoint: /
    # At least one of 'requests.run' or 'requests.send' is required below.
    requests:
      # Run a command to generate traffic. Requests should be sent to the Optic proxy, the address of which is injected
      # into 'run.command's env as OPTIC_PROXY or the value of 'run.proxy_variable', if set.
      run:
        # The command that will generate traffic to the Optic proxy. Globbing with '*' is supported.
        # Required if specifying 'requests.run'.
        command: your-test-command
        # The name of the environment variable injected into the env of the command that contains the address of the Optic proxy.
        # Optional: default: OPTIC_PROXY
        proxy_variable: OPTIC_PROXY

Verify traffic

Next, run optic capture against your OpenAPI file. This will run your test command and compare any captured requests (i.e. requests sent to the Optic proxy) against the OpenAPI spec.

optic capture openapi.yml
Running "npm test"...

× GET /books/{book}
  × 200 response
  'created_at' is not documented
× GET /books
   × 200 response
  'id' does not match type number. Received "WjE9O1d8ELCb8POiOw4pn"

In this example, Optic detected diffs between captured traffic and the OpenAPI spec. Not a problem, we can use optic capture to automatically update our spec using the traffic we collected.

Updating your OpenAPI

Run optic capture again, with the --update interactive flag. This will update your spec using the captured traffic, and keep any $refs and comments intact!

optic capture openapi.yml --update interactive
✔ GET /books/{book}
  ✓ 200 response
    'created_at' has been added
✔ GET /books
  ✓ 200 response
    'id' type has been changed to string
openapi.yml
components:
  schemas:
    Book:
      type: object
      properties:
        id:
          type: string # was 'number' before
        name:
          type: string
        author_id:
          type: string
        updated_at:
          type: string
        created_at:    # new property documented
          type: string
      required:
        - id
        - name
        - author_id
        - created_at   # new property marked as required
        - updated_at

Run in CI

alt

Set up CI to verify traffic against your OpenAPI spec, and if it is out of sync, run --update to update it locally.

Calling optic run in your CI pipeline runs optic capture on every OpenAPI spec with a capture config in the optic.yml file. It also runs breaking change checks and other API standards your team has configured and reports on the state of all the API changes being proposed.

Next: Set up Optic in CI