One Way to Improve API Guidance

I’ve seen my share of API Design guidelines. I’ve even contributed to a few. Consistent across those style guides, standards documents, and requirements pages is that we crafted them without the benefit of technical writing or information architecture professionals. Despite having the best of intentions, we left opportunities for conveying our design expectations in better and more useful ways.

One simple yet powerful addition to any design requirements page is the inclusion of examples formatting in the company’s schema of choice. These examples can be easily copied/pasted and modified in the editor of choice, removing the ambiguity of personal interpretation or possible typos.

A picture of a slide from 2018 commenting on the importance of examples from Jasmine Mithani.
A picture of a slide from 2018 commenting on the importance of examples from Jasmine Mithani.

Let’s take a closer look at what I mean. Here is a hypothetical example of an API rule a business might adopt for interface consistency:


Pagination

When retrieving a collection of similar items, a caller may desire only to retrieve a subset. The caller may also need the ability to progress through subsets. To paginate through a collection, an API SHOULD provide a pair of query parameters: limit and offset.


That is solid guidance and a step toward encouraging APIs that behave more consistently within a domain. However, even within that tiny snippet, several nuanced elements need to be translated correctly to an OpenAPI’s YAML. We also assume that developers are well versed in YAML conventions. In my experience, OpenAPI is a means to an end, not a topic of voluntary study and application. As a result, whoever is writing the API description writes just enough to get their description to validate against the OpenAPI schema and moves on. This minimum viable description checks a box but falls short of being good enough for integrators:

paths:
    /users:
        get:
            responses:
                '200':
                description: success
            parameters:
                - $ref: "#components/limit"
                - $ref: "#components/offset"
components:
    schemas:
        limit:
            description: the limit
        offset:
            description: the offset

Publishing an API describing pagination this way meets the letter of the rule, it fails to demonstrate the spirit: lowering comprehension overhead.

Part of doing the right thing lies with the API designer. But the guidelines, by providing examples that can be copy/pasted, can do a tremendous amount to make that job more manageable. If it was the dev team creating APIs, the benefit is limited. Ten? Now we see some benefit. Dozens of teams across a company? At that scale, the consistency and speed possible by copy/pasting fully realized guidance directly into a design begins to add up.

So after the description of the pagination guidelines above, include an example that they can easily copy, paste, and customize into their own work, like below. Then continue for each and every other API design feature that would benefit from a more consistent approach. Those writing API descriptions will thank you for it.

paths:
    /users:
        get:
            responses:
                '200':
                description: success
            parameters:
                - name: offset
                    in: query
                    required: false
                    description: The index of the first item to retrieve. Indices are zero-based
                    schema: 
                        type: integer
                        format: int32
                        minimum: 0
                        default: 0
                - name: limit
                    in: query
                    required: false
                    description: The number of items to retrieve at once. <<insert API-specific default here, including if there is a maximum value>>
                    schema: 
                        type: integer
                        format: int32
                        minimum: 1
                        maximum: 1000
                        default: 20