I'm working on an iPhone/iPad/Android app which communicates with a JSON API.
The first release of the version of the app is complete, and now additional phases of development are taking place. In the additional phases, the app needs to integrate with a new version of the API and allow the user access to additional features such as new screens or modified behaviour within existing screens. The app does however need to be backwards with previous versions of the API.
What is the best practice for tackling such a requirement? I could of could do checks throughout the code:
if (APIVersion == 1) {
} else if (APIVersion == 2) {
} else if (APIVersion == ....) {
}...
But I'm concerned about the scalability of this approach. The factory method comes to mind but I'm not sure how far this would get me.
Thanks, Mark
API backward compatibility In microservices systems, you need to make changes to service APIs in a backward compatible manner. A change to the API should not break existing consumers of the API.
Backward compatibility can be used to preserve older software that would have otherwise been lost when a manufacturer decides to stop supporting older hardware. Classic video games are a common example used when discussing the value of supporting older software.
Versionless APIs is meant in the same way as Serverless. Serverless is not about "no servers". Serverless means, you don't have to deal with servers. Versionless means, you don't have to deal with versions.
API compatibility exampleAn API is backward compatible if a client (a program written to consume the API) that can work with one version of the API can work the same way with future versions of the API.
Release of a new API version is a very rare thing. Usually you can achieve backward-compatibility just by adding new optional parameters or new methods. For example, if you had method named search
, but now you are dissatisfied with the way it works, you may deal with it in various ways:
If the change is simple you may add a new mode
parameter which defaults to mode1
(so it's backward-compatible). If user supplies mode2
you detect it with a proper if
condition as you proposed yourself. (Also, usually you can think of a better name than "mode".)
If the change is a big one, you may add a new search2
service which uses the new interface. Then you mark search
method as deprecated (but still working and backward-compatible). Usually when you do this, you can refactor your code in such a way, that almost all of the logic is inside the search2
method, and your old search
method calls search2
internally with modified parameters (and re-formats the results appropriately). If you do this properly, you won't ever need to change search
method anymore. When you alter your tables etc. - you will only need to modify search2
.
My point is, avoid releasing N+1
-st version of an API. Such big release implies major changes in ALL of your methods, not just one. Many major APIs never released version 2 of their API, they still use version 1, just slightly modify portions of it, as in the example above.
If you are absolutely sure about releasing N+1
-st version of you API, create new entry points for ALL of your methods. If you had a folder named services
, create new one named services-v2
. Refactor your services
code so that it uses the most of services-v2
. If you think it's overkill, then I think you don't need N+1
-st version of your API yet.
BTW, do not confuse centralized APIs (like Google Maps) with distributed ones (like Android). Android releases new API versions all the time, because there are billions of Android servers (each Android device is one), and they all cannot be simply upgraded remotely by Google. The next version of Android is still backward-compatible with the previous one, the number is increased only to indicate new features. E.g. You can still run apps built for Android 3.0 on Android 7.0 (the user might get some extra warnings, but the app will run). Android-app developers use these numbers in order to describe "minimum requirements" for their apps. Whereas, centralized APIs usually increase their version number to indicate a major backward-incompatible change.
I guess you already have a separation of concerns. I mean, getting the datas for your app is only done through the Model (for example).
So you only have to change the model.
What I suggest is that there is only one entry point: the "router" file. This file checks the API version needed, and loads the correct file. This way, you get different files for each API. The "router" file won't be very big, and each new API version will have its own file, so you're not mixing everything.
For example, in the "router" file:
function dispatch() {
switch (APIVersion) {
case 1:
use('file.1.ext');
break;
case 2:
use('file.2.ext');
break;
case 3:
use('file.3.ext');
break;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With