Docs
API Contract Testing

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

optic.yml
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.

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

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.

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.

optic.yml
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.

optic.yml
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

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:

modedescription
documented (default)Automatically apply observed changes to existing endpoints only.
interactiveInteractively prompt and confirm observed changes to new and existing endpoints.
automaticAutomatically apply observed changes to new and existing endpoints.

Run in CI

Calling optic run in your CI pipeline runs optic capture on every OpenAPI specification 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. Learn more about running in CI here

alt