Test APIs with Behavior Snapshots
Optic tests that the runtime behavior of an API matches what is documented in its OpenAPI specification. Traffic from your integration tests and end-to-end tests is compared to the schemas documented in the OpenAPI spec. If the traffic does not match, diffs get reported and the test fails.
optic capture
is snapshot testing for your APIs. Set up CI to check against your OpenAPI spec, and update using the --update
flag locally
- Stop accidental/unplanned API changes from being released
- Make sure your API is working as-designed
- Verify your OpenAPI documentation is accurate (API + docs in sync)
The optic capture
command runs your existing tests and reports which endpoints are working as-designed and which endpoints do not match the documentation in OpenAPI.
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"
Each capture is configured in the optic.yml
file. Learn more here
capture:
openapi.yml:
server:
command: npm start # your server start command
url: http://localhost:8080 # where your server starts
requests:
run:
command: npm test # your test command
This configuration tells Optic how to start your test server, where it runs, and how your tests are started.
When diffs are reported you can fix them manually, or use Optic to help you update the snapshot (OpenAPI) to match the actual behaviors. This makes it easy for developers to document new endpoints and changes to existing ones. Whenever Optic updates your specification, it does it in exactly the right places, following each $ref
to the correct file/line.
Documenting a new endpoints
optic capture openapi.yml --update interactive
Optic will ask you to confirm the path pattern before adding a new endpoint to your specification. All IDs in the URLs will be replaced with parameters in this syntax {parameterName}
:
/books/{bookId}
? Is this the right pattern for GET /books/pale-blue-dot › - Use arrow-keys. Return to submit.
❯ yes
no
ignore
skip
Optic adds the new operation to the specification:
openapi: 3.1.0
paths:
/books/{bookId}:
get:
responses:
"200":
description: 200 response
content:
application/json; charset=utf-8:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/Book"
next:
type: "null"
has_more_data:
type: boolean
required:
- data
- next
- has_more_data
Updating existing endpoints
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
Optic modified only these lines of OpenAPI. It did not overwrite the descriptions, $refs
etc.
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
Capture your test traffic
Optic starts a local proxy 1) forwards traffic to an instance of your API and, 2) compares that traffic to your OpenAPI specification. You need to specify the server's address in the optic.yml
under server.url
. You also need to have your tests send requests through our proxy using the OPTIC_PROXY
environment variable.

- Capture traffic from a locally-running API and test suite
- Capture traffic from a development or production environment
- Import a Postman collection
- Import a HAR
Option 1: Local API + Test Suite
Optic captures traffic by running your existing tests through a local proxy:
To start capturing your test traffic, run:
optic capture init /path/to/openapi.yml
The quickest way to explore Optic is to send mock requests defined in the optic.yml
. We know this won't scale, but you can get it working right away and automate the traffic after you see how Optic works.
capture:
openapi.yml:
server:
command: npm start # start your server
url: http://localhost:8080 # the url where it runs
requests:
send:
- path: /
method: GET
- path: /users/create
method: POST
headers:
content-type: application/json;charset=UTF-8
data:
name: Hank
Now when you run the capture command, Optic will send requests to your API. In this example one to GET /
and one to POST /users/create
.
optic capture openapi.yml
Option 2: Development or Production Environment
The quickest way to try Optic is to send a few mock requests defined in our YAML format. We know this won't scale, but you can get it working right away and automate the traffic after you see how Optic works.
capture:
openapi.yml:
server:
url: https://dev-123.your-api.com # the url where it runs
requests:
send:
- path: /
method: GET
- path: /users/create
method: POST
headers:
content-type: application/json;charset=UTF-8
data:
name: Hank
Now when you run the capture command, Optic will send requests to your API. In this example one to GET /
and one to POST /users/create
.
optic capture openapi.yml
Option 3: Import a Postman collection
Optic learns from the example traffic in your Postman Collection. You can save examples in the Postman Client by clicking Save as Example
button in the bottom right:

optic capture openapi.yml --postman collection.json
Option 4: Import a HAR
Optic supports the HAR format (opens in a new tab). If you can export HAR logs from your API framework, gateway, browser, etc Optic can process it and compare the behavior of the API to the specification:
optic capture openapi.yml --har traffic.har
Run in CI
When you run capture
with one of the above configurations, Optic will compare the test traffic to your OpenAPI specification. When the traffic does not match -- it will exit 1
. You can set this up in CI to prevent undocumented API changes from getting released.
optic capture openapi.yml
Update the snapshot (OpenAPI)
OpenAPI is difficult for many developers to read/write. Optic helps them update the OpenAPI when the API behavior does not match what is documented. Just pass in the --update
flag.
optic capture openapi.yml --update
There are 3 update modes:
mode | description |
---|---|
documented (default) | Automatically apply observed changes to existing endpoints only. |
interactive | Interactively prompt and confirm observed changes to new and existing endpoints. |
automatic | Automatically apply observed changes to new and existing endpoints. |