Making a useful REST API Specification
Tags: api, webdev
Published: 2022-12-21 07:02:33

Getting people to work well with your API is hard work, and documenting it is perhaps the best way to do so. A popular way to document REST APIs is through a machine-readable specification such as OpenAPI. This comes with a few benefits, mostly that there is widespread tooling for generating and transforming OpenAPI specifications. For example, there are tools for documentation generators, mock servers, and so much more.

This is not a tutorial for REST APIs or OpenAPI and surrounding tooling: see other tutorials to learn the specification language and tooling. This post is about making your OpenAPI specifications properly useful to help developers.

## Tip 1: Precise types

This should go without saying, but the types inside your API specification should be specific in order to be useful. The main way I see this appear is that some specification generators seem to default to "string" for everything, even if something else makes sense. In an analysis of 1154 specifications from [OpenAPI directory](https://github.com/APIs-guru/openapi-directory), I found that 60% of the field types were strings. Many of these were instances that made sense, such as IDs or names, but many were misused types: for example, there was a year value encoded with type "string," and a boolean value with type "string" and enum "true" or "false". Using too-broad types such as strings can make it harder to understand the specification, and decrease the effectiveness of certain tools.

For example, see the following snippet from the specification for the [bbc.com REST API](https://github.com/APIs-guru/openapi-directory/blob/3a6ef952c6ace9257716a554852d5e151f3ad899/APIs/bbc.com/1.0.0/openapi.yaml#L3781):

```yaml
embargoed:
  enum:
    - "true"
    - "false"
  type: string
```

It uses the string "true" where a boolean value could be more appropriate, which can lead to confusion as other fields might properly use booleans.

## Tip 2: Examples

Only 10% of OpenAPI specifications provide examples directly inside the API, based on the same analysis as before. But embedded examples are huge for readability: they help people get started with the API immediately.

As a demonstration, consider the following specification for a price schema (modified from the amadeus API). It defines two properties `base` and `currency`, each with string type.

```yaml
Price:
  properties:
    base:
      description: Amount without taxes
      type: string
    currency:
      type: string
```

For a consumer of this API, it’s not immediately clear how to fill in this schema. Of course, precise types would help: the base amount could be matched with a regex pattern specifying valid currency quantities, and the currency could be selected from an enum of valid currencies.

But consider a consumer trying to understand the API: It is better to have examples so they can try calling the API quickly.

```yaml
Price:
  properties:
    base:
      description: Amount without taxes
      example: "632.70"
      type: string
    currency:
      example: "USD"
      type: string
```

Now, with the examples filled in, the consumer of the REST API understands the types better. The currency field could be a currency code like "USD" or "EUR," and the amount is a string representation of a decimal number.

## Summary

To make an OpenAPI specification useful for documenting a REST API, it is important to use precise types and include examples. Using precise types helps to clearly define the data being used in the API, and examples provide a way for developers to quickly understand how to use the API. By following these best practices, you can create a useful and effective REST API specification.