When maintaining a public API that should be used by an unknown number of clients, downward compatibility is a crucial topic. Different clients use different versions of the API and usually the operator of the API is interested in having as many users as possible.
When the service is released the first time everything is perfect. There is the implementation of the domain logic and there is exactly one version if the REST API. All clients that depend on the service use this one API.
But the perfect world won’t last forever. As the development of new features proceeds, it is very likely that the API evolves and changes as well. It is also very likely that not every client will migrate to the current version of the API right away.
The worst thing to do, is implementing different versions of your domain logic. Features that don’t change the API and bugfixes would have to be implemented more than once and in different contexts. Maintenance would be a nightmare.
So what is the alternative? One way to tackle this problem is to design the service as an magnanimous writer.
If having more than one version of the domain logic is a bad idea, the one implementation should obviously be the implementation of the newest REST API. To make sure that the request of a client hits the correct endpoint the version of the API needs to be somewhere in the request. A summary of different ways where to put the version is described here.
In my opinion the version should be part of the of the Content-Type respectively the Accept header. That way the version is part of the representation in which a resource is requested.
The REST endpoints for older versions do not call the domain logic, but call a mapper that transforms the data in the request into the format the domain logic expects it. The result is then tranformed into a format that fits in version 1 of the REST API.
Implementing such a mapper may not always be easy. It is important to find the balance between cost and use. But if the cost of writing a mapper is not so high it is fairly easy to integrate it, because it should not be necessary to adjust the previous mappings.
The magnanimous writer enables a system to provide the necessary number of API versions at the same time.
It must be considered that the response time for older clients increases as more and more versions are produced because all mappings have to be traversed. That might also be an advantage because it increases the nee to migrate to the current version.
I provided a Spring-Boot example implementation on Github.
Top comments (0)