Documenting REST APIs by Proxy

Published by Aidan Cunniffe on February 3rd, 2019

The number of APIs a developer interacts with on a monthly basis has rapidly grown over the last decade. This can be mainly attributed to the growing trust in 3rd party SaaS companies to handle core business processes and the rising clout of microservices, containerization and serverless architectures. Even within established companies, the dozen APIs that ran the business have been split into hundreds of specialized ones.

Writing microservices with a well-defined purview allows different teams to make their own architecture choices, innovate faster, and write code that is far more readable and maintainable. This is a good thing, but all benefits come alongside trade-offs, and for many companies that trade-off is the cost of stitching all these services together.

Teams employ many different approaches, but the problem is the same: learning the shape of each API, documenting that shape and communicating it to other developers has become a prerequisite to connecting services.

The magic tooling almost every developer we spoke with has articulated:

  • works with their existing codebase
  • produces API Specs automatically w/o manual support
  • requires no manual annotation or revisions once the spec is produced
  • automatically keeps itself up-to-date on check-in. "[Docs] should be a first-class artifact"

We want this too for the APIs we develop, but when you look at the landscape of tools it's hard to find anything that checks all the boxes.

Traditional Approaches

In order of most to least favorable:

  • Rely on a self-documenting framework: This can work well if you are writing greenfield APIs and are willing to fight the frameworks a bit + give up some of the ergonomics of more popular API frameworks.
  • Manual Documentation w/ a Standard Spec: Using a tool like Swagger gives you a great way to communicate the shape of your API, but maintaining it is a manual process and docs drift from source of truth over time.
  • Unstructured Readmes: Well written notes in wiki or checked into the repo can be very useful and are still popular today. They obviously require a lot of manual labor to maintain, but for slower-moving teams they can be effective.
  • Slack, Email, F2F: Many API specs are documented as co-workers ask one another questions. This can work ok when teams are using question-answer tools like StackOverflow internally to persist insights.

API Integration Tests as Source of Truth

More and more teams have realized the benefits of using integration tests as the spec for their API. On these teams it's common to direct co-workers to model_controller_test.rb if they need to know how to access certain functionality exposed by the API.

Using tests as the source of truth for your API Spec brings a lot of advantages:

  • Tests are a great abstraction for defining a contract since a test fails if the assertions don't line up with the behavior of the component tested.
  • Tests are tightly coupled to your code and most build systems will fail if some tests don't pass. This is a built-in guard against doc drift.
  • Tests verify the actual behavior of your API making them more accurate. Every developer has found docs that says the API behaves in a way it clearly does not.
  • You [hopefully] already have them :) And if you don't, writing them is already a goal.

Integration tests have one major drawback -- they don't produce a standard API Spec like a Swagger as an artifact. Without that capability the test files themselves are the reference so you can't display the them in a nice GUI, generate client SDKs, or share them with developers who are not on your team.

Documenting Proxies

The idea of using proxy servers to document APIs isn't particularly novel -- obviously if a proxy sees every request/response pairing it can infer the parameters, headers, schema and possible responses for any endpoint. The time for this technology to gain prominence has arrived as developers have started to trust systems that learn for themselves rather than being explicitly programmed.

The open questions now are both about data.

  • What is the right environment to deploy a documenting proxy?
  • How do you ensure that it collects the high quality data it needs to infer a comprehensive and accurate API Spec?

The answer to both these questions is tests -- specifically the integration tests your team uses as the source of truth. Test environments handle dummy data, interact with mock services, and aren't impacted by the the small latencies adding a proxy introduces. They also run all your API integration tests providing a rich source of data to the proxy on every check-in.

A documenting proxy combines your integration tests into a declarative API Spec that can be output as the API Spec artifact. This gives you and your teammates another incentive to write great tests, because when you do, you get great API documentation for free.

Optic -- an open source documenting proxy

We built Optic (YC S18) because we believe developers shouldn't be allowed to write API docs. Teams should focus on writing great tests and the code that passes them. So we wrote, and open-sourced, Optic to help every team create reliable docs.

The Optic Flow

  1. Add optic.yml file to the root of your API repository.

    project: myteam/backend-auth-api
    test: npm run test
    paths:
    -/login
    -/logout
    -/user/preferences
    -/user/password
    -/user/password/reset
  2. Add an Optic test fixture to your repository. These fixtures route your test traffic through an Optic proxy whenever the optic-watching environment variable is present. The Optic proxy runs locally so none of the test requests or the post-processing is done on the cloud. Find or create a fixture for your codebase here

    //psudocode for example fixture
    if enviroment['optic-watching']:
        routeThroughProxy(request)
    else
        runNormally(request)	
  3. Run your tests with Optic to turn your test into API Docs.

    testuser$ optic spec
    All Tests Passed! Analysis Complete!
    Documented 6 endpoints from 22 tests in 3.905 seconds

    example publish

Conclusion

Combining solid API integration tests with a documenting proxy makes it possible to generate great API docs from your tests. Once teams can reliably generate accurate API documentation they can start automating even more parts of software development. More ideas on that next time :)

If you're interested in what we've built, we'd love to talk and we welcome all contributions to our GitHub repos. You can learn more about setting up Optic for your project here.

Thanks for reading!