What’s Wrong With OpenAPI?

How we struggled with API documentation on our projects and went a bit crazy

Konstantin Malyshev
Level Up Coding

--

Photo by Kevin Ku on Unsplash

Are you happy with API documentation in your company? Almost certainly not. We weren’t by a long shot.

We won’t go into the sad consequences of error-filled, outdated or non-existent API documentation, but why is this seemingly easy-to-solve issue such a big problem on so many projects?

The reason is simple: developers truly hate describing API. It’s boring and takes ages. Nobody likes wasting their time. Even if you happen to make them do it once, during updates nobody’s going back in.

Take OpenAPI — the “most convenient” language to describe REST API. It’s painful to use, a developer will never do it until he absolutely has to (this case perfectly describes the attitude towards OpenAPI).

Let’s take the simplest API with one endpoint:

GET /users/{id}

Let’s say the endpoint responds with a code 200 message like:

{
"id": 123,
"name": "Tom"
}

To achieve it the programmer has to write 23 (!) lines of code in OpenAPI:

openapi: 3.0.1
paths:
/users/{id}:
get:
parameters:
- name: id
in: path
required: true
schema: {}
responses:
200:
content:
application/json:
schema:
required: [id, name]
type: object
properties:
id:
type: integer
example: 123
name:
type: string
example: "Tom"

Real APIs tend to take not just 23 lines but thousands (here’s a 13-thousand-line Twitter API example).

There are, of course, instruments like OpenAPI visual editors, where instead of coding one can use a graphic interface (like https://stoplight.io/), but they are not very helpful: numerous lines of OpenAPI code are replaced with equally numerous mouse clicks.

As a result in real-life projects (averaged from a number of studies):

  • Roughly half the time API is not described at all;
  • In about 25% of projects it’s described manually (the so-called “Spec First” approach). On many projects this documentation is not kept up-to-date afterwards;
  • The remaining 25% have API documentation generated using the code itself (so-called “Code First” approach).

This last option seems like a great one. Many frameworks allow generators that create OpenAPI specs based on code. And it’s a truly great way when it works, but often it doesn’t, because:

  1. On many projects (especially big ones) API is created not only by developers, but also: architects, systems analysts, QA engineers, stakeholders from other departments. One such team meeting can easily require 10 people, and not all of them are capable of generating OpenAPI documents based on code. It inevitably leads to OpenAPI files being manually written, exchanged within the team, commented on, edited, etc.
  2. Many projects (especially big ones) use outdated languages and frameworks, for which there are no OpenAPI spec generators. That’s how some APIs end up being undocumented (and often they’re the most important ones, used for many years!).
  3. OpenAPI spec generators often have errors, which get in the way of generating what’s needed (here’s an example of a generator bug). It’s especially vivid in large long-term projects, with multiple languages and frameworks used for different parts of the system. Each framework uses its own OpenAPI generator, so at least one of them having a bug is very likely. If the generator breaks down, this API stays undocumented. Nobody will do it manually, that’s guaranteed.
  4. OpenAPI generators are capable of creating only a part of the needed documentation. But there are also detailed descriptions, use cases, message examples (crucial for bigger projects). One has to do it manually and somehow stuff it into the code, for the generator to create documentation based on it.

Interestingly, all these drawbacks are most vivid in bigger projects. Hence larger systems almost always use “Spec First”.

A quick summary (with approximate numbers):

  • 50% of API documentation is outdated or doesn’t exist;
  • 25% (often on larger projects) has to be manually written by developers using OpenAPI;
  • 25% of projects solve the problem by using generators. But this approach has limitations that get in the way of using it in the other 75% of cases.

Consequences of a seemingly tiny issue of “stiff API description language” are astounding! This “little” issue leads to developers sabotaging writing API documentation, and many of existing APIs have none.

Our own experience confirmed it. Over a few years we tried all possible API documentation options: writing manually on some projects, generating from code on others, hoping for the best on the rest.

It came to a point when we decided we didn’t want to live like this. There must be an easier way to describe API. What we ended up finding was a revelation.

When developers talk about API structures in their normal working habitats, you’ll never see them draw on whiteboards or send anything resembling OpenAPI documents in chats. Instead they draw and send examples of data, each of which needs to go to the endpoint (or be received in response). These exchanges look literally like this:

How do I use your API? POST something like this to /users: …

Showing an example is the simplest way of sharing knowledge. Seems like that’s how our brains are wired. One can spend hours explaining something and then show an example — and it all falls into place right away.

Can we use a data example to formally describe a data scheme? Of course! We just need to agree on rules for interpreting the example. In most cases these are intuitively clear. Let’s take the same example:

{ 
"id": 123,
"name": "Tom"
}

This example immediately implies four requirements for data structure:

  1. Data must be an object;
  2. The object must contain properties “id” and “name”;
  3. The “id” property must be of “integer” type;
  4. The “name” property must be of “string” type.

This raises a question: what if we want to add some other “weird” rule, which cannot be expressed using a data example? For instance, we say that “name” is not mandatory. Once again, let’s eavesdrop on our unsuspecting developers and see how they do it. In such cases they add a comment to the data, like:

// This field is optional!

This informal exchange can also be easily formalized. We’ve decided that we’ll append a small json-object as a comment, which would describe all additional requirements of the property in question. So we have:

{ 
"id": 123,
"name": "Tom" // {optional: true}
}

Magnificent!

If we’d known how long it would take to get from the idea of a new language to a working version usable in real-world projects, we would have freaked out and said it was crazy. But, luckily, we didn’t, so we got to work. Here are our key principles:

  1. The language must be intuitive;
  2. It must make use of the terms and constructs familiar to developers;
  3. It must be capable of describing not only REST API, but all other APIs (JSON-RPC, for example). This will allow reusing existing libraries in different kinds of APIs;
  4. The language must be 100% compatible with OpenAPI (to avoid difficulties when creating a converter from OpenAPI and back).

After two years we arrived at a rather pleasant version. Here’s an example description of the above API (from the beginning of the article):

JSIGHT 0.3

GET /users/{id}
200
{
"id": 123,
"name": "Tom"
}

“JSIGHT 0.3” is the language name and version. All else should be clear without comments. Just a reminder — in OpenAPI the same took 23 lines.

This very simple example illustrates our core idea. However, we equipped our language with all the must-have features and more: user types, macros, includes, inheritance, regular expressions, enums, comments, headers, queries, markdown, etc.

In addition to the language we developed the necessary toolkit:

  • An online editor with syntax highlighting;
  • JSight → OpenAPI converter.
  • HTML-documentation generator (for the document to look good);
  • Message validator (to check that incoming and outgoing messages comply with the API specification).

We tried all three on our own projects, and here’s the summary:

  • Describing API seems to not equal suffering anymore. At least, none of the developers wished to return to OpenAPI :)
  • Hurray! Our projects now have 100% exact and up-to-date API documentation (thanks to the message validator, which makes sure the developer fixes API specs if they are even a little bit outdated).
  • The validator was easily incorporated into all frameworks including legacy code (we created adapters for C/C++, Go, PHP, Rust, Python, Java, NodeJS, Lua, and it took a while).

The language also turned out to be usable for drafting right during discussions about future API structure. Here’s how:

  • One participant (an analyst, for example) shares his screen and opens the editor;
  • The team discusses a prospective API, the analyst writes down ideas right away using our language, and everyone else sees what is being written;
  • At the end of the meeting the analyst saves an API draft in the cloud (yes, we created a cloud too) and sends the document to everybody in the group chat.

Now developing API happens right during one group meeting. With OpenAPI it was unimaginable — there’s no way to do quick drafts. Before this, meetings had to be repeated 2–3 or more times, and between them the analyst had to write down ideas in OpenAPI — the way he/she understood them from the previous meeting. Then he/she sent the OpenAPI file to participants, and (obviously!) it turned out that team members misunderstood each other and needed to meet again. The new language completely changed our API design workflow.

And yet.

We admit that we went a bit crazy in the process. Creating a new language these days is something completely out of the ordinary. At least for REST API the whole world uses OpenAPI. Would people want to switch from something they got used to?

Not an easy question to answer. The history of the industry says that complex machine-oriented technologies always give way to simple intuitive ones. If the developer struggles with something, it will eventually be replaced. This is how the switch from XML to JSON happened once upon a time, and how SOAP gave way to REST. It will probably happen to OpenAPI too. But when? How? What will replace it?

Can our crazy project become this replacement?

We believe it can! But, of course, only time will tell.

Curious? Check out our open-source code on GitHub:
https://github.com/jsightapi/online-editor-frontend and star it if you like it. The project website: https://jsight.io.

Resources:

--

--

Software architect | SOA | High-load | TOGAF | Telecommunications | Autonomous Vehicles