Skip to content

Commit ce12712

Browse files
author
Matthew Fisher
committed
feat(controller): check client against API version
Before locking the API version, we needed some way to ensure that we did not break the client. This was done by comparing the client's version against the server. If there was a mismatch on the minor or major release versions (as noted in Semver 2.0.0[1]), the server would refuse the request. Because we have locked the API version, it would make sense to test against that to see if the client is compatible with the API. If not, then the client should upgrade. This also modifies the current behaviour to warn the user on a minor version mismatch. If there is a minor version mismatch between the client and the server, it will press onwards and display a warning, advising the user to upgrade. If there is a major version mismatch, then the API server will refuse the request as before. [1]: http://semver.org/
1 parent b0f2a6a commit ce12712

4 files changed

Lines changed: 26 additions & 6 deletions

File tree

client/deis.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070

7171
__version__ = '1.1.0-dev'
7272

73+
# what version of the API is this client compatible with?
74+
__api_version__ = '1.0'
75+
7376

7477
locale.setlocale(locale.LC_ALL, '')
7578

@@ -392,10 +395,18 @@ def _dispatch(self, method, path, body=None, **kwargs):
392395
url = urlparse.urljoin(controller, path, **kwargs)
393396
headers = {
394397
'content-type': 'application/json',
395-
'X-Deis-Version': __version__.rsplit('.', 1)[0],
398+
'X-Deis-Version': __api_version__.rsplit('.', 1)[0],
396399
'Authorization': 'token {}'.format(token)
397400
}
398401
response = func(url, data=body, headers=headers)
402+
# check for version mismatch
403+
server_api_version = response.headers.get('X_DEIS_API_VERSION')
404+
if server_api_version is not None and server_api_version != __api_version__:
405+
self._logger.warning("""
406+
! WARNING: Client and server API versions do not match. Please consider upgrading.
407+
! Client version: {}
408+
! Server version: {}
409+
""".format(__api_version__, server_api_version))
399410
return response
400411

401412
def apps(self, args):

controller/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
"""
22
The **api** Django app presents a RESTful web API for interacting with the **deis** system.
33
"""
4+
5+
__version__ = '1.0.0'

controller/api/middleware.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
from django.http import HttpResponse
44
from rest_framework import status
55

6-
from deis import __version__
6+
from api import __version__
77

88

99
class VersionMiddleware:
1010

1111
def process_request(self, request):
1212
try:
13-
# server and client version must match "x.y"
13+
# server and client version must match the major release point
1414
client_version = request.META['HTTP_X_DEIS_VERSION']
15-
server_version = __version__.rsplit('.', 1)[0]
15+
server_version = __version__.rsplit('.', 2)[0]
1616
if client_version != server_version:
1717
message = {
1818
'error': 'Client and server versions do not match. ' +
@@ -26,3 +26,8 @@ def process_request(self, request):
2626
)
2727
except KeyError:
2828
pass
29+
30+
def process_response(self, request, response):
31+
# clients shouldn't care about the patch release
32+
response['X_DEIS_API_VERSION'] = __version__.rsplit('.', 1)[0]
33+
return response

controller/api/tests/test_api_middleware.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.test import TestCase
1010
from rest_framework.authtoken.models import Token
1111

12-
from deis import __version__
12+
from api import __version__
1313

1414

1515
class APIMiddlewareTest(TestCase):
@@ -28,10 +28,12 @@ def test_x_deis_version_header_good(self):
2828
"""
2929
response = self.client.get(
3030
'/v1/apps',
31-
HTTP_X_DEIS_VERSION=__version__.rsplit('.', 1)[0],
31+
HTTP_X_DEIS_VERSION=__version__.rsplit('.', 2)[0],
3232
HTTP_AUTHORIZATION='token {}'.format(self.token),
3333
)
3434
self.assertEqual(response.status_code, 200)
35+
self.assertEqual(response.has_header('X_DEIS_API_VERSION'), True)
36+
self.assertEqual(response['X_DEIS_API_VERSION'], __version__.rsplit('.', 1)[0])
3537

3638
def test_x_deis_version_header_bad(self):
3739
"""

0 commit comments

Comments
 (0)