How to keep an API documentation up-to-date

3 October 2022

Actually, it is really important to not do unnecessary work. If nobody needs your documentation then you probably shouldn't write it.
I also have to disagree with those who say “it is better to have some documentation than none”.
If your company is good enough to write documentation then do it properly.
Poor documentation is worse than missing documentation.

This point is controversial. If you are not yet sold, don’t buy it - you won’t lose much anyway. Put some effort into keeping your docs up-to-date and you’ll be fine.
If nevertheless your documentation becomes outdated from time to time there is a way to, at least partially, make it a part of the continuous integration.

Developers naturally don’t like writing documentation. For numerous reasons but this is a topic for a different discussion.
The problem is that while avoiding to write the docs developers end up using tricks and hacks. The most popular is to write documentation in meta-programming style. Right above the code. Something as follows:

<?php

use OpenApi\Annotations as OA;

class ListPostController {
    /**
     * @OA\Get(
     *     path="/api/posts",
     *     @OA\Response(
     *         response="200",
     *         description="The list of posts"
     *     )
     * )
     */
    public function execute()
    {
        // ...
    }
}

There are multiple drawbacks for this approach.

Documentation shall not have an impact on the code itself.

If you use metaprogramming for documenting then be prepared that one day your metacode will affect the real code.
I’ve seen multiple times when meta-code parser package requirements were in conflict with a project's necessary upgrades.
Guess what happened after resolving those conflicts and upgrading the packages? The documentation stopped "working" because meta-syntax was not matching the new version.

It has no benefits that many try to sell you.

Many developers say that metadocs help to keep documentation up to date while it actually doesn't. The main argument is that the documentation resides very close to its subject which helps to keep it up to date.
Beside the fact that it actually does not that would be a good point if the level of the code and the documentation are the same. In the case of web API documentation is on a different level of "abstraction".

This documentation is a high level contract.

It means that it can reside anywhere even before the actual code appears.
It is a very good practice to write the documentation that represents requirements for an API before actually implementing it.
Thus it may be written by a consumer(a.k.a. frontend) team or a tech-analyst and implemented afterwards by the backend team.

What's the point?
The main idea here is that documentation is as good as your team tries to keep it.
If they put much effort then likely it might almost never become misleading/outdated. Regardless of the approach the team uses.

Good thing is that in the 21st century we can add documentation validation into continuous integration process.

Warning! It is applicable to the technical documentation. Particularly this case is about OpenAPI specification (you might be familiar with swagger).

Requirements

The minimum that you need is an openapi specification document that contains information about your API.
It may be generated or manually written.
Also, your application has to support psr7 request and response format.
If it does not you will have to look for an adapter/bridge.

How to.

For a symfony application it is as easy as to install openapi-validator-bundle and configure it according to the readme.

After that every time when there is a response returned from your app the validator middleware will check if both the request and the response match your documentation.
On a mismatch it will throw an error. Missing documentation will also lead to an error.
If your application has a good functional test coverage or you have smoke tests it will help you to find issues automatically.

Your app is not symfony related?

If you are using zend/laravel/yii or something else then you have to manually integrate thephpleague/psr7-validator into your workflow.
It is much easier than it might sound though it will require some boilerplate.

Keep in mind

Don’t forget that validation has to happen only in the dev/staging environment - incorrect requests or responses shall not cause failures in a prod environment.
If your app made it through CI/CD/testing without a notice then you likely can't do a thing if there will appear validation errors on production. Also, the validation process consumes resources and may harm the overall performance.

Validator effectiveness fully relies on the quality of the documentation. If the documentation says:

poor documentation

paths:
    /publications:
        post:
            responses:
                "200":
                    description: "Create post and return its details"
                    schema:
                        type: "object"

then the only thing that the validator can do is to check if the response contains an object. Yet if you declare the object details it makes your documentation more relevant and the validator will become more efficient.

rich documentation

paths:
    /publications:
        post:
            responses:
                "200":
                    description: "Create post and return its details"
                    schema:
                        type: "object"
                        required:
                            - id
                            - title
                        properties:
                              id:
                                  type: integer
                                  minimum: 1
                              title:
                                  type: string

Documentation is important yet the running software is more important.
Don’t fall into the cargo cult writing documentation blindly. Do it on purpose and do it well.

Don't take everything plain: we have to challenge and prove the information we face.

Here is what really helps me to do it.