Three Reasons why OpenAPI is the Best Documentation Platform for your API

October 28, 2022
Written by
Reviewed by

Three Reasons why OpenAPI is the Best Documentation Platform for your API

OpenAPI is a specification for a machine-readable description of HTTP web services. If you have never heard this name, maybe you are familiar with Swagger, which is how it was known in its early days.

In this article I’m going to provide a brief introduction to OpenAPI, and give you the three main reasons why I think it can be a great addition to your API project.

What does OpenAPI look like?

To use OpenAPI in your project, you have to create a specification document that describes your API or web service. OpenAPI specifications can be written in JSON or YAML formats. The OpenAPI Specification page describes in detail what the contents of this document should be, but if you want to have a rough idea of the format, here is a fragment of a document:

openapi: 3.0.3
info:
  title: My Example API
  version: 2.3
servers:
  - url: https://awesome.app.io/api/v2
tags:
  - name: users
    description: User Resource
paths:
  /users:
    get:
      tags:
        - users
      summary: Get all the users
      operationId: getUsers
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedUser'
        '401':
          description: Invalid credentials
      security:
        - basic_auth: []
    post:
      tags:
        - users
      summary: Register a new user
      operationId: newUser
      responses:
        '201':
          description: User created

I hope this small fragment gives you an idea of what OpenAPI is. The specification allows you to define every possible input and output of every endpoint, so it provides a complete and exhaustive description of how your service works. Did you notice the reference to a schema called PaginatedUser in the definition of the 200 response? Schemas are an important part of OpenAPI, they describe in detail what the structure of request and response bodies are, including the type of each attribute and any validation requirements. There is a section in the OpenAPI document where all the schemas are described. Here is the schema definition for PaginatedUser:

  PaginatedUser:
    type: object
    properties:
      pagination:
        "$ref": "#/components/schemas/StringPagination"
      data:
        type: array
        items:
          "$ref": "#/components/schemas/User"

You can see that this schema has references to other two schemas called StringPagination and User. The User schema is defined as the type of the elements in an array, indicating that endpoints that use this schema return a list of users. Here is the User schema:

  User:
    type: object
    properties:
      id:
        type: integer
        readOnly: true
        description: The user's id.
      username:
        type: string
        minLength: 3
        maxLength: 64
        description: The user's username.
      email:
        type: string
        maxLength: 120
      password:
        type: string
        writeOnly: true
        minLength: 3
      about_me:
        type: string
        nullable: true
        maxLength: 140
      posts_url:
        type: string
        format: url
        readOnly: true
    required:
    - email
    - password
    - username
    description: This schema represents a user.

Here you can see how powerful and expressive the OpenAPI syntax can be. Some of the attributes of the User schema are read-only by the client (meaning that will be returned in responses, but not accepted in incoming requests), others are write-only, such as password. Many attributes include validation requirements as well, such as nullable or not, maximum length and being required or optional.

Written descriptions are supported at pretty much all levels, so you can combine machine-friendly and accurate definitions with your own documentation intended for human consumption.

If you’ve seen enough here to pique your interest and would like to have some hands-on time with the OpenAPI specification format, the freely available Swagger Editor is a fun, interactive editing tool to learn the basics.

Screenshot of the Swagger Editor

There are also OpenAPI plugins and extensions for text editors, and dedicated GUI editors that do not require you to know the complete OpenAPI syntax.

Now that you know what the OpenAPI Specification is, you may be wondering why you may want to adopt it for your project. In the sections that follow, I will give you my main three reasons, plus a bonus fourth (you always have to have a bonus, right?).

Reason #1: auto-generate your API documentation

If you tried the Swagger Editor, you probably figured this one out already. The OpenAPI specification is so thorough that it can be automatically translated into documentation for your API that is directed to your developer users.

The preview pane in the Swagger Editor is a great example of this. OpenAPI renders a complete documentation page directly from the specification entered in the editor area. The preview includes all the endpoints and schemas, and combines auto-generated sections with the associated text descriptions that you entered. It even provides a user interface to authenticate against the actual service and send test requests straight from the page.

You may or may not like how this auto-generated documentation looks. A valid criticism I have heard is that Swagger styled documentation makes it difficult to navigate large projects, because all the endpoints and schemas are rendered sequentially, without any navigation or search options. The great news is that while OpenAPI originated from the Swagger tooling, it has grown beyond it, and now there is a healthy ecosystem of tools, including several alternative documentation renderers.

Want to see some of the options that are available? Below you can see a few documentation screenshots as they render a project of mine.

The first one uses Stoplight Elements:

Screenshot of API documentation rendered with Stoplight Elements

The next one uses RapiDoc:

Screenshot of API documentation rendered with RapiDoc

Here is how the same documentation looks when rendered with ReDoc:

Screenshot of API documentation rendered with ReDoc

And last but not least, here is the same project rendered with the Swagger toolset:

Screenshot of API documentation rendered with Swagger UI

As you see, there are many different styles, so you are likely to find one that matches your taste. If you want to look for more, this page has a long list of documentation renderers.

These renderers all work from the same OpenAPI specifications, so you can freely switch between them without changing anything in your OpenAPI document or your project. Also, they are all open source, so you have the option to modify them if you have the inclination!

Reason #2: auto-generate your API clients

Okay, now you know that you can have nice, automatically generated documentation from your OpenAPI specification. What else can you do with it?

If you have an API or web service, you likely want to make it easy for your users to work with it. One way many companies (including Twilio) do that is by distributing client libraries for several programming languages. The libraries hide the tedious task of creating and sending raw HTTP requests, so many developers find it more convenient to work with a web service when a client library exists for their language of choice. The problem is that having to develop and maintain client libraries for a handful of languages can be a huge effort if done manually.

Here, one more time, OpenAPI comes to the rescue. Since all the information regarding inputs and outputs for every endpoint are included in the specification document, client libraries for all the languages of interest can be rendered from it. In fact, the Swagger Editor tool I recommended above can auto-generate client libraries for about two dozen programming languages and technologies using the Generate Client option.

Generate Client option in Swagger Editor

What do you get when you generate a client library? As an example, here is what you get when you select Python:

  • A zip file with a complete and ready-to-use Python package, including *setup.py*, *requirements.txt* and standard package structure.
  • Schemas implemented as Python classes, with setters and getters for all attributes. Setters include validation logic.
  • Tags implemented as Python classes, with methods for each endpoint.
  • Documentation files, with Python-specific examples for all endpoints.
  • Testing suite for all endpoints. Testing logic is not included, only scaffolding for all the test functions is provided.

Having all this work done automatically can make a huge difference, even if you need to do some manual edits to the generated code. And as with documentation, if the Swagger client generator does not fit your needs, there is a long list of alternatives that you can explore.

I think client generation alone might be enough to convince many companies to jump on the OpenAPI train. At Twilio, we are currently in the process of migrating all our client libraries to be generated from our OpenAPI specifications. As of October 2022, the Go and Java libraries are already created from OpenAPI, while the remaining ones are soon going to be as well.

Reason #3: auto-generate your back end

You have seen how OpenAPI specification files can be useful in generating client code. Could something be done on the server-side?

The details stored in specification documents can be used to generate servers as well as clients. The only difference is that in a client, the logic in each endpoint is well understood and can be generated, while in the server, what each endpoint does is specific to the application and cannot be directly derived from the OpenAPI details.

Nevertheless, it is possible to generate a fairly complete back end that includes models for all the schemas, attribute validation, and function scaffolding for all the endpoints. Swagger Editor, once again, provides a good example of this with its Generate Server option.

Generate Server option in Swagger Editor

You can also pick from server implementations in several languages. Generated servers are complete packages that include model definitions, parameter validation, functions for all endpoints that are ready for you to edit, test framework and some of them even a Dockerfile.

Bonus reason: auto-generate your OpenAPI specification!

So there you have it, you now know the three reasons why I always recommend adopting OpenAPI. We’ve looked at documentation, client generation and server generation. It would seem as if there is nothing else OpenAPI can help auto-generate, and yet, there is.

Did you think about how you would incorporate the OpenAPI specification into the development workflow of your project? In many cases it makes sense to treat the specification document as an additional source file that is updated along with the rest of the project. This can work well for teams that are very disciplined and have a robust testing and validation strategy, but other teams may find it a struggle to keep the OpenAPI document perfectly synchronized with the service it describes.

How about auto-generating the OpenAPI specification itself?

We’ve seen how server-side scaffolding code can be generated from an OpenAPI document. Would it be possible to go in the reverse direction and automatically generate the OpenAPI document from working server code?

This is an idea that has taken off in the Python community. The FastAPI web framework automatically generates an OpenAPI specification document, using the information about the endpoints and schemas that is normally provided when coding the server logic. This framework uses type hints and Pydantic models, so it has all the details that it needs to write the specification document. And not only that, but it also adds a /docs endpoint that automatically renders the documentation on the live server.

Consider this FastAPI example from the official documentation:

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item

Here you can appreciate how Python type hints are used along with Pydantic to create very accurate descriptions, which help FastAPI perform validation checks and generate the OpenAPI specification document.

Unfortunately I do not know of any examples of this type of integration for other languages. But after FastAPI came up with this powerful solution, several implementations of this idea for other Python web frameworks have emerged.

The other Python integration with OpenAPI I want to mention is one that I wrote. It’s called APIFairy and gives Flask developers a similar auto-generated OpenAPI specification that is based on Marshmallow schemas instead of type hints and Pydantic. Using APIFairy, you can define the inputs and outputs of each endpoint using decorators:

@users.route('/users/<int:id>', methods=['GET'])
@authenticate(token_auth)
@response(user_schema)
@other_responses({404: 'User not found'})
def get(id: 'The id of the user'):
    """Retrieve a user by id"""
    return db.session.get(User, id) or abort(404)

The authenticate, response and other_responses decorators, along with arguments and body (not shown in the example above) allow the Flask developer to provide complete details about each endpoint. The APIFairy extension for Flask then uses this information to authenticate, validate incoming requests, format outgoing responses, and also generate the OpenAPI document. As with FastAPI, the /docs endpoint renders the documentation for the server on the fly. See this Getting Started guide if you want to explore this option further.

Conclusion

So there you have it. Three reasons to adopt OpenAPI, plus a bonus one. If you want to learn what other tools exist in the OpenAPI ecosystem, this page has a nice list.

If you’d like to see some examples of real-world APIs rendered through OpenAPI, have a look at the following:

I can’t wait to see what you build with OpenAPI!

Miguel Grinberg is a Principal Software Engineer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool project you’d like to share on this blog!