diff options
| author | Tom Christie | 2014-12-16 15:34:19 +0000 |
|---|---|---|
| committer | Tom Christie | 2014-12-16 15:34:19 +0000 |
| commit | 6e51e4f5cdec4f4580360a487d7bf5ebdef08709 (patch) | |
| tree | 2ccc09ad64e8e257ee76b6fdf1d6bf949b1269be /rest_framework/versioning.py | |
| parent | b6ee784240b3c7f6cd62af5b6fe6d1014d7bf6d4 (diff) | |
| download | django-rest-framework-6e51e4f5cdec4f4580360a487d7bf5ebdef08709.tar.bz2 | |
Versioning first pass
Diffstat (limited to 'rest_framework/versioning.py')
| -rw-r--r-- | rest_framework/versioning.py | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py new file mode 100644 index 00000000..2ca8efff --- /dev/null +++ b/rest_framework/versioning.py @@ -0,0 +1,96 @@ +# coding: utf-8 +from __future__ import unicode_literals +from rest_framework.reverse import _reverse +from rest_framework.utils.mediatypes import _MediaType +import re + + +class BaseVersioning(object): + def determine_version(self, request, *args, **kwargs): + msg = '{cls}.determine_version() must be implemented.' + raise NotImplemented(msg.format( + cls=self.__class__.__name__ + )) + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + return _reverse(viewname, args, kwargs, request, format, **extra) + + +class QueryParameterVersioning(BaseVersioning): + """ + GET /something/?version=0.1 HTTP/1.1 + Host: example.com + Accept: application/json + """ + default_version = None + version_param = 'version' + + def determine_version(self, request, *args, **kwargs): + return request.query_params.get(self.version_param) + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + url = super(QueryParameterVersioning, self).reverse( + viewname, args, kwargs, request, format, **kwargs + ) + if request.version is not None: + return replace_query_param(url, self.version_param, request.version) + return url + + +class HostNameVersioning(BaseVersioning): + """ + GET /something/ HTTP/1.1 + Host: v1.example.com + Accept: application/json + """ + default_version = None + hostname_regex = re.compile(r'^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$') + + def determine_version(self, request, *args, **kwargs): + hostname, seperator, port = request.get_host().partition(':') + match = self.hostname_regex.match(hostname) + if not match: + return self.default_version + return match.group(1) + + # We don't need to implement `reverse`, as the hostname will already be + # preserved as part of the standard `reverse` implementation. + + +class AcceptHeaderVersioning(BaseVersioning): + """ + GET /something/ HTTP/1.1 + Host: example.com + Accept: application/json; version=1.0 + """ + default_version = None + version_param = 'version' + + def determine_version(self, request, *args, **kwargs): + media_type = _MediaType(request.accepted_media_type) + return media_type.params.get(self.version_param, self.default_version) + + # We don't need to implement `reverse`, as the versioning is based + # on the `Accept` header, not on the request URL. + + +class URLPathVersioning(BaseVersioning): + """ + GET /1.0/something/ HTTP/1.1 + Host: example.com + Accept: application/json + """ + default_version = None + version_param = 'version' + + def determine_version(self, request, *args, **kwargs): + return kwargs.get(self.version_param, self.default_version) + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + if request.version is not None: + kwargs = {} if (kwargs is None) else kwargs + kwargs[self.version_param] = request.version + + return super(URLPathVersioning, self).reverse( + viewname, args, kwargs, request, format, **kwargs + ) |
