We often handling API server updates including backwards-incompatible changes when upgrading web applications. At the same time we update the client part, therefore, we did not experience any particular difficulties.
Though, in the case of handling API updates for a mobile app, the process of upgrading applications in the user's phone does not occur simultaneously. Moreover, users may have various versions of the application, and we have to keep all API versions up and running.
An app should have a nice versioned API: changes and new functionalities have to be implemented in the new API versions, not just in one same version. Existing clients can continue to use the old compatible API version with the new one. New or upgraded clients can use a new version.
DRF supports multiple versioning schemes:
AcceptHeaderVersioning – transfer of the version number through the Accept request header:
URLPathVersioning – adding the version to a resource address of a variable (the path is specified in the DRF through the VERSION_PARAM parameter):
NamespaceVersioning – the version is given through the url namespace:
HostNameVersioning – the version is set by the domain name:
QueryParameterVersioning – transfer of the version through the GET parameter:
The first versioning method is described in the Django REST Framework documentation.
Creating Serializer and ViewSet:
If we need to change/delete/add a field, we create a new serializer and change fields in it.
And then we redefine the get_serializer_class method in AccountViewSet:
That’s one way to redefine the serializer, permission class and other methods in ViewSet.
As well, I found a small application for versioning.
I did not use it, though, we got from the description that we can set the Serializer and Parser and use them to set the transform’s base class.
Setting the basic version:
And we do so for every new version:
The backwards methods would apply from the end to the beginning when receiving data from client, i.e. 0004, 0003, 0002. When sending data to the client, the forwards would apply in direct order 0002, 0003, 0004.
The basic idea was to split the API into the modules and use the class inheritance.
The following directory structure is:
base - the first version of our API.
Further, in the versioned folder, we created a folder for each version. In this project we had two external clients: iOS and Android + our WEB client. The WEB client has always used the latest version of the API.
Each successive API version was prepared this way: we made changes in the existing API v2; after the iOS and Android client release (they released them at the same time), we’ve created v3 and stopped making changes to v2. We could change Version 3 before the next release of the external clients.
DRF uses classes to create ViewSet, Serializer, Permission. We used inheritance between the API versions to not fully copy ViewSets and Serializers.
Further, we generally connected urls.py to the first API version:
We removed the first_name, last_name fields and added the full_name fields. Then we created v2 keeping the backward compatibility and addde the serializers.py, views.py, router.py directories and files:
inheriting the basic version:
Updating the urls.py root:
You may notice that we’ve inherited UserViewSet, and we did not have to update BookViewSet, that’s why we used the first version of the view.
Read Also: SaaS Development Trends
It can be quite difficult to manage the API versions, especially if you want to do it properly. You can find pros and cons in each versioning method. And the inheritance method proved to be good due to small number of versions in our project.
When dealing with one of our projects (LookSMI media monitoring platform) we have to handle the huge volume of data – and its quantity is constantly growing. At the same time, we must run quick searches with smart rules. In this article I'll explain how we have achieved required performance.
One of our recent projects includes the functionality of an inline code editor. This code editor needed to be highly extensible and have custom features. To address this, we chose Codemirror v6 due to its peculiar architecture - it is highly customizable, and all the additional features are provided into codemirror engine as Extension objects.