From HTTP to OpenAPI with Optic

I’ve been using Optic’s CLI, an OpenAPI tool that does a bunch of things including diffing OpenAPI descriptions and comparing HTTP traffic with OpenAPI. My use case was an established API that didn’t have an OpenAPI file yet – using Optic we could create one as a starting point, and then move to a design-first workflow to make the changes that I was there to help with. For this blog post, I’ve used the example of https://api.joind.in as an excellent representation of an API still in use, but without an OpenAPI file and not built with code that a code generator would recognise.

The basic premise goes something like this:

  • Configure Optic to set where your API is, and how to run the API tests.
  • Configure your API tests (or other API traffic source – I used a collection of curl requests which was enough to begin!) to test against the URL in an environment variable.
  • Run Optic in capture-and-update mode, pointing to an empty/template OpenAPI file.

At the end of the process, you’ll have an OpenAPI file with the operations, parameters and data structures that Optic observed from the API traffic. What you won’t have is anything fit for users to use, because there are no examples, descriptions, or any other user-helping content. What you will have is a structure to start adding those things into (and I have some suggestions when we get to that point).

Configure Optic

Give Optic the location of your live or sandbox API, and the command to run the test suite for your API.
Here’s how my configuration looks:

capture:
openapi.yaml:

# Run with "optic capture openapi.yaml --update interactive"
server:
url: https://api.joind.in/v2.1/
requests:
run:
command: ./test.sh

“API Tests” is a pretty generous term for what I used! Ideally you’d run your end-to-end or integration tests – but this API doesn’t have any of that yet. So I hacked together a series of curl commands to run from a shell script; the main aim is to put some API traffic through the Optic proxy so it can see what’s going on. You can definitely do better for your own APIs, but I also secretly love that this was enough to get things moving on this project so I’m sharing it :)

#!/bin/bash

curl -s -o /dev/null $OPTIC_PROXY/users
curl -s -o /dev/null $OPTIC_PROXY/users/18888888881
curl -s -o /dev/null $OPTIC_PROXY/users/11

curl -s -o /dev/null $OPTIC_PROXY/events
curl -s -o /dev/null $OPTIC_PROXY/events?filter=hot
curl -s -o /dev/null $OPTIC_PROXY/events?start=10&resultsperpage=20
curl -s -o /dev/null $OPTIC_PROXY/events/8377
curl -s -o /dev/null $OPTIC_PROXY/events/8387/tracks

The main thing to note is that rather than hitting the actual API endpoints, I’m using an environment variable $OPTIC_PROXY. In fact, the API requests all go to Optic, and Optic passes them on to the actual API, checking the request and response data along the way, then returns the response to us.

Proxy and Capture

Let’s go! Run Optic, and give it the name of a file to update with its findings:

optic capture openapi.yaml --update interactive

Tada! You have an OpenAPI file! You can’t really do anything with it at this point, but you have a great structure in place.

Crucially, you can re-run and re-update the file at any time, which is a great way to catch API drift situations where code changes have been made and not propogated through to the OpenAPI file. In an ideal world, changes would be design-first, and then implemented promptly. I don’t live in the ideal world though, so tools like Optic help a lot.

Now draw the rest of the Owl, I mean OpenAPI

The basic structure of an API description would be incredibly tedious to do by hand, so we’ve saved ourselves a lot of work. But OpenAPI files should be much more than what you can learn from sniffing traffic. They are the API experience you offer to producers and consumers who have to work with your API, so there’s more work to do.

It doesn’t all have to be done in one go, but take the time to tick off as many of the following as you can:

  • Fill in the fields in the info section such as contact and license, and definitely title. This stuff is easy to gloss over but as we move more and more to API discovery by machines or through catalogs, the metadata is more important than ever.
  • For each Operation, add a summary, a description, and as many response examples as you can think of. Include error responses, these are vitally important for tools such as SDK generators to know how to handle the various structures that might be returned by your API.
  • For each schema and parameter, add a description, any additional format information you can, and an example. These really help users to know how to use the fields available to them.

It might seem like a lot of work! You can consider hiring specialist API documentation writers to help gather together the information you need and work through building out the detail of the OpenAPI description if you don’t have the expertise or bandwidth in house. Tech writers understand users and APIs, and can help keep everyone aligned.

An LLM Helping Hand

One thing to note here if you’re trying to construct an OpenAPI file is that since everyone publishes their OpenAPI files and they’re very formulaic, an LLM can help to speed up the process. Please approach this part of the post with caution: these tools don’t “know” anything and will easily mislead you if you don’t know either the API or OpenAPI itself very well. The tools are also non-deterministic, so what works one day might do something else completely next time. However I do use LLMs with OpenAPI files when the OpenAPI file is under source control and changes are made one at a time, under my supervision, and reviewed thoroughly by experts.

How did I use an LLM in my own project? Actually the Joind.in API had some hand-written markdown documentation with some good explanations of the various endpoints and parameters. Using the OpenAPI from Optic, and a generated PDF of the API documentation, and telling it not to use any other inputs at all, I did get a reasonable first attempt at an OpenAPI document out of the end of the process! As with all these projects, there’s a lot of human work needed (tip: tell your LLM “now suggest and make improvements” a few times, why this works I am unclear but it does! See also my earlier remarks about having it in source control and using small steps, I find whole sections went missing sometimes) before you’d want to give the result to a user, but the machines have done the boring/repetitive parts for us, and now the humans bring their critical thinking skills as expert reviewers.

As more and more organisations embark on API modernisation projects, keeping their tried-and-tested APIs online and updating the processes around them, I expect to see more tools like this in use. If you do a project like this yourself, I’d love to hear how it went and what you’d add to the advice I shared here.

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.