django-rest-framework: api versioning

后端 未结 2 2042
借酒劲吻你
借酒劲吻你 2020-12-04 12:50

so googling around it appears that the general consensus is that embedding version numbers in REST URIs is a bad practice and a bad idea.

even on SO there are strong

2条回答
  •  再見小時候
    2020-12-04 13:13

    UPDATE:

    versioning is now properly supported.


    There are some answers from your link:

    We found it practical and useful to put the version in the URL. It makes it easy to tell what you're using at a glance. We do alias /foo to /foo/(latest versions) for ease of use, shorter / cleaner URLs, etc, as the accepted answer suggests. Keeping backwards compatibility forever is often cost-prohibitive and/or very difficult. We prefer to give advanced notice of deprecation, redirects like suggested here, docs, and other mechanisms.

    So we took this approach, 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/
    

提交回复
热议问题