django-rest-framework: api versioning

By | February 18, 2014

Django Rest Framework is a very solid api framework, but it doesn’t provide out-of-box versioning mechanism, here is my attempt to implement version specific APIs.

The goal is to achieve something like


http://localhost:8000/api/(resource)/
http://localhost:8000/api/v1/(resource)/

plus allowing clients to specify the version in request header (X-Version), here is how we did it.

Structure in side the API app:


├── __init__.py
├── middlewares.py
├── urls.py
├── v1
│ ├── __init__.py
│ ├── account
│ │ ├── __init__.py
│ │ ├── serializers.py
│ │ └── views.py
│ └── urls.py
└── v2
├── __init__.py
├── account
│ ├── __init__.py
│ ├── serializers.py
│ └── views.py
└── urls.py

project urls.py:

url(r'^api/', include('project.api.urls', namespace='api')),

api app level urls.py:

from django.conf.urls import *

urlpatterns = patterns('',
    url(r'', include('project.api.v2.urls', namespace='default')),
    url(r'^v1/', include('project.api.v1.urls', namespace='v1')),
)

version level urls.py

from django.conf.urls import *
from .account import views as account_views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('account', account_views.AccountView)
router.register('myaccount', account_views.MyAccountView)
urlpatterns = router.urls

create a middleware to switch to the correct code by changing the path_info, please note there is a caveat that namespace (‘api’) defined in project level urls is not flexible and needs to be known in middleware:

from django.core.urlresolvers import resolve
from django.core.urlresolvers import reverse


class VersionSwitch(object):

def process_request(self, request):
    r = resolve(request.path_info)
    version = request.META.get('HTTP_X_VERSION', False)
    if r.namespace.startswith('api:') and version:
        old_version = r.namespace.split(':')[-1]
        request.path_info = reverse('{}:{}'.format(r.namespace.replace(old_version, version), r.url_name), args=r.args, kwargs=r.kwargs)

Sample url:

curl -H "X-Version: v1" http://your.domain:8000/api/myaccount/

My original answer on stackoverflow.

4 thoughts on “django-rest-framework: api versioning

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.