Keep up-to-date with out breaking issues

If you’ve been comfy working along with your previous API for a very long time, it may be onerous to undertake a brand new API model; notably in the event you by no means designed for it. On this information, I’ll present you a way to undertake even drastically new iterations, with minimal churn to your code.
Let’s say that we’re a vet clinic, and we now have an app that will get some knowledge from our API, codecs it as HTML, after which prints it to the console. You’ll be able to extrapolate how we would construct a totally useful internet or cell app from this define.
Once we designed this app, we had a really particular thought for a way it might look, so we designed our mannequin and API round these necessities. It really works completely for us, and we’re very proud of it.
However now we now have a brand new requirement: we now have to indicate the cat’s favorite meals. The backend staff already helps this, however it’s solely accessible of their new API model. Lets take a look on the new schema they’ve despatched us:
Seems they’ve made loads of modifications to the brand new schema, and there are a number of points:
- we don’t wish to assist the brand new values of
breed
, and so they useCamelCase
as a substitute of thesnake_case
we wish. colors
is a set of enums as a substitute of thegray
andbrown
booleans we wishid
andownerId
are UUIDs as a substitute of the integers we wishappointments
are lacking from the cat schema; they’re solely accessible from a very completely different API operation
Think about for a second that our app is very large: if we had been to undertake this new schema as our mannequin, the modifications can be large, and would require intensive regression testing. We will’t justify that quantity of effort when all we wished was for a brand new property to be added.
If we undertake a few of the principals of Hexagonal Architecture (particularly Ports and Adapters), we are able to insulate our app from most of those points. We will undertake the brand new API model, add the brand new function, and alter little or no of our current code. All of that is potential with an adapter the converts the brand new schema to the mannequin we’re accustomed to.

Port
In software program phrases, a port is the interface that defines the contract we wish to have fulfilled.
enjoyable interface Horn
enjoyable honk()
Adapter
An adapter is the implementation of the port’s interface. There could be a number of variations that may be swapped out and in as wanted, and even on the fly, or layered with useful programming.
class CarHorn: Horn
override enjoyable honk()
println("Beep")
class TruckHorn: Horn
override enjoyable honk()
println("BURRRRRRRRRP")
Outline our Port
So, how can we use Ports and Adapters to assist us? If our objective is to make use of the identical Cat
mannequin as earlier than, then all of the port actually must do is get a Cat
by its id. However first we have to reconcile the distinction between the previous integer id
and the brand new UUID
. Fortunately, the 2 could be simply expressed as a String
, so our port will use that. We will afford a small compromise by updating our Cat
mannequin to make use of a String id
.
Implement the v1 Adapter
Now, lets give you a v1 adapter to implement our port. It’s quite simple, as a result of all it does is delegate the duty to the ClientV1
.
Implement the v2 Adapter
Subsequent we have to create an adapter forClientV2
. This one is a little more complicated as a result of it must make two API calls and merge the outcome into the unique Cat
mannequin. We’ll additionally take this chance to get the brand new favouriteFood
discipline from the CatDtoV2
.
With a view to really use this new CatsDao
port, we should replace our CatUi
to make use of it as a substitute of the ClientV1
. Then we should replace our most important
methodology to inject an adapter. Then we are able to safely render the cat from both API, and the favorite meals, if current.
So now we’ve efficiently adopted a very new UI with minimal churn. However why did we preserve a V1 adapter?
Cause 1: Security
It’s usually beneficial to nonetheless assist the previous API and use a function flag to slowly roll out the replace or shortly roll again in case of a difficulty.
Cause 2: Legacy Information
If the v2
API doesn’t have entry to all the previous knowledge, then we’ll want a option to fall again to v1
.
To work round these issues, we now have 2 new adapters. The toggled
adapter makes use of a function flag to find out whether or not we delegate to the v1
or backCompat
adapter, and backCompat
will try and get the Cat
from v2
, falling again to v1
if not discovered.
Our authentic app had an issue, and the enhancements thus far haven’t modified that. After efficiently releasing assist for favouriteFood
, we now wish to assist all the brand new colors accessible within the v2
schema. The Cat
mannequin doesn’t assist this, however updating it might complicate our ClientV1
.
Earlier than, this is able to have been an enormous downside. However now that we now have the instruments to insulate our inner mannequin from new API variations, we are able to take it a step additional and insulate it from the (now) legacy v1
schema by making the ClientV1
return a brand new CatDtoV1
, and updating the adapter to transform from CatDtoV1
to a Cat
. As soon as that’s finished, will probably be a lot safer to assist this new function, whereas nonetheless supporting each API variations.
Don’t neglect to make the corresponding replace to the v2
adapter.
With this information, it is best to be capable of undertake new API variations with minimal churn to your current code. All it requires is to switch your direct dependency on the consumer with a port, applied by an adapter that converts from the brand new mannequin to 1 you’re comfy with. Please let me know within the feedback if this helps you sort out an onerous migration. Good luck!
For the complete supply code, see the repo under: