Hands-on with Optic
Get started by exploring Optic through an interactive demo. In this demo, you will:
- Lint an OpenAPI spec
- Diff an OpenAPI spec against a previous version
- Check for breaking changes between two OpenAPI specs
- Verify that an OpenAPI spec is accurate
Start by cloning the demo repo:
git clone git@github.com:opticdev/bookstore-example.git
and installing Optic:
npm install -g @useoptic/optic
Viewing our spec
In the cloned demo repo, you will find an OpenAPI spec (openapi.yml
) that describes an online bookstore and has a couple of endpoints for adding, getting, and updating books and authors.
Optic hosts your OpenAPI spec and keeps track of the history of your specification. You can view your API documentation and see how it has changed over time. To do this, you'll need to upload your OpenAPI spec to Optic.
First, log in to Optic:
optic login
Next, add
your OpenAPI spec to Optic
optic api add openapi.yml --history-depth=0
--history-depth=0
will add all the history of this API to Optic, so you can see exactly how your API has changed over time, and see when breaking changes were introduced.
You should see that Optic has uploaded openapi.yml
and is now being tracked.
Adding API ~/bookstore-example/openapi.yml
✔ Optic Bookstore Demo Spec is now being tracked.
View: https://app.useoptic.com/organizations/{yourOrganizationId}/apis/{apiId}
Click and follow the link in the output to be able to see your API and all of its history.

You will also notice that an x-optic-url
has been added to your OpenAPI spec. This is how Optic keeps track of spec files in different places. Commit this change.
git add .
git commit -m "Add x-optic-url"
Linting an OpenAPI spec
This repo has 3 branches. Check out the first one which adds a GET /authors
endpoint. Start by switching to the branch add-author-list-endpoint
.
git checkout add-author-list-endpoint
Now lint the OpenAPI spec with optic lint
:
optic lint openapi.yml
invalid openapi: paths > /author > get > responses > 200 must NOT have additional properties
112 | responses:
113 | 200:
114 | description: Successfully fetched authors
115 | application/json:
116 | schema:
117 | type: object
118 | properties:
Oops - it looks like something is wrong with this OpenAPI spec. There is a missing content
key where application/json
should be.
Let's fix that:
112 | responses:
113 | 200:
114 | description: Successfully fetched authors
+ | content:
115 | application/json:
116 | schema:
117 | type: object
118 | properties:
Now rerun lint
to confirm that the spec is fixed:
optic lint openapi.yml
Diffing API specs
Next, check out the add-type-to-book-request
branch, which adds a type
to the Books request:
git checkout add-type-to-book-request
Now, try running diff against main, and checking it against the API's standards:
optic diff openapi.yml --base main --check
The rules are configured in the optic.yml
file in the repo. Learn more about how to configure your own API standards.
...
Checks
FAIL POST /books
added rule [error]: prevent changing request property to required
x cannot add a required request property 'type' to an existing operation. This is a breaking change.
at paths > /books > post > requestBody > content > application/json > schema > properties > type (~/bookstore-example/openapi.yml:208:5096)
...
It looks like Optic has detected a breaking change here! Adding a new request body property that is required will break existing calls that don't include this request property. Make sure to fix this by setting a default value to type
if it's not already set.
Optic also looks for a number of other common breaking changes, so you can rest easy and know you aren't accidentally adding breaking changes. You can see more about what breaking changes we detect in our GitHub repo (opens in a new tab)
Try adding the --web
flag to this command - Optic will render the results in a web browser so you can see exactly what changed.
Now check out the last branch, add-dob-to-author
, where the date of birth of authors is being added.
git checkout add-dob-to-author
Try running diff against main
again, and checking it against the API standards.
optic diff openapi.yml --base main --check
...
Checks
FAIL PATCH /author/{author_id}
added rule [error]: request property naming check
x dateOfBirth is not snake_case
at paths > /author/{author_id} > patch > requestBody > content > application/json > schema > properties > dateOfBirth (~/bookstore-example/openapi.yml:151:3939)
...
It looks like dateOfBirth
isn't consistent with the naming rules for the API, because the standards are configured to require snake_case
properties.
Optic isn't just an OpenAPI linter - Optic can be configured to run forwards only governance (i.e. only newly added endpoints will be affected by rules). This is useful when you have an existing API and want to incrementally standardize or roll out new rules. Read more in the forwards only checks guide.
Running in CI
Optic can be configured to run in CI so you don't need to worry about manually checking every change.
Here are some pull requests where Optic has been set up in CI with the examples from above:
- Adding type to the Book request (breaking change) (opens in a new tab)
- Adding date of birth to Author (inconsistent naming) (opens in a new tab)
Optic comments on pull requests with a preview of the API and a visual diff and can be configured to fail CI so that you can control how your API changes over time.
If you want to set up CI, follow the GitHub or GitLab guides.
Verifying your OpenAPI spec
Finally, it's time to verify that the API implementation matches the OpenAPI spec.
Switch back to the main
branch:
git checkout main
If you haven't added openapi.yml
to Optic yet, add it now.
optic login
optic api add openapi.yml --history-depth=0
For this tutorial, a server is running on https://bookstoreexample.optic.dev
. Use this server to verify the implementation.
In this case, you're using a remote server, but you can route traffic anywhere whether that be a locally run server or your staging or production servers.
Start by making a request to the server to see what it responds with:
curl https://bookstoreexample.optic.dev/books
You should have gotten a list of books back from this endpoint. Now use Optic to capture traffic and use it to verify the implementation. To do this, you need to start Optic up to capture traffic:
optic capture openapi.yml https://bookstoreexample.optic.dev --reverse-proxy
You should notice a message that says something like:
> Optic proxy is running at https://localhost:8000 - send traffic to this host. Traffic will be forwarded to https://bookstoreexample.optic.dev and will be recorded
Any traffic sent to https://localhost:8000
will be forwarded to https://bookstoreexample.optic.dev
. To get the list of books through the capture proxy, make a request to https://localhost:8000/books
.
Optic runs a local reverse proxy server so that it can monitor requests and use that information to update or verify an OpenAPI spec.
Make a couple of other requests to capture some traffic you can use to verify the OpenAPI spec.
curl https://localhost:8000/books
curl -X POST https://localhost:8000/books --data '{"name": "Animal Farm", "author_id": "6nTxAFM5ck4Hob77hGQoL"}' --header 'Content-Type: application/json'
curl https://localhost:8000/books/123
Notice that Optic is capturing traffic as you make these requests:
» Optic proxy is running at https://localhost:8000 - send traffic to this host. Traffic will be forwarded to https://bookstoreexample.optic.dev and will be recorded
help Press [ Enter ] to finish capturing requests
✔ 3 requests captured
You can also run Optic in system-proxy
mode which will use the system proxy to capture traffic. This is useful for when you want to capture traffic in your web browser so you don't need to reroute requests to the Optic reverse proxy.
It looks like the OpenAPI spec is out of date with the API implementation.
Diff 'name' is not documented
operation: post /books
73 | application/json:
74 | schema:
75 | type: object
76 | properties: Undocumented 'name'
77 | id:
78 | type: string
79 | required:
Diff 'author_id' is not documented
operation: post /books
73 | application/json:
74 | schema:
75 | type: object
76 | properties: Undocumented 'author_id'
77 | id:
78 | type: string
79 | required:
The POST /books
endpoint is returning two extra fields (name
and author_id
) - go ahead and use optic update
to update the spec to match:
optic update openapi.yml --all
You should now see Optic has updated your OpenAPI spec. Confirm the updates by running optic verify
:
optic verify openapi.yml
Great! You've confirmed the OpenAPI spec matches the API implementation. Go ahead and commit these changes:
git add .
git commit -m "Updated OpenAPI spec to match API response"
Finally, upload the spec to Optic Cloud.
optic verify openapi.yml --upload
Once you've uploaded this, you'll see in the spec in Optic that you've uploaded verification information to some of the endpoints.

Optic stores captured traffic in a temporary directory. If you want to clear out old traffic that you've collected, run the optic capture clear
command.
What's next
In this tutorial you have:
- Linted an OpenAPI spec
- Diffed OpenAPI spec against a previous version
- Run API checks against our OpenAPI spec
- Verified the implementation of our OpenAPI spec
You've only scratched the surface of what Optic can do. Here's a list of things you might want to check out next:
- Set up Optic in CI using GitHub or GitLab to run automated API checks and verify your API.
- Explore Optic's built in API standards
- Talk to us and see how Optic can fit into your API program