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
orhttps://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
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
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
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.