Django REST Framework

A word from our sponsor...

"I think most people just make the mistake that it should be simple to design simple things. In reality, the effort required to design something is inversely proportional to the simplicity of the result. As architectural styles go, REST is very simple."

Fielding

In a nutshell

  • RESTful Web APIs
  • Uses 1.3's class based views
  • Creates Web Browseable APIs

Motivation

Browseable APIs - a call to Arms!

Fist

Eh?

  • Something's not right here.
  • RESTful systems are supposed to be self-describing.
  • We're building Web APIs...
  • ...but they're not Web browseable.

Wtf

It doesn't need to be this way

  • We don't need to be designing systems that are awkward to interact with.
  • There are some difficulties with building HTML powered APIs...
  • ...but there are workarounds.

API explorers are not the answer.

  • Introduce an unnecessary indirection.
  • The API itself should be self-describing.

Explorer

This stuff matters!

It's not about eye candy. If we design our APIs to be browse-able, they will be:

  • Better designed.
  • Faster to work with.
  • More transparent, open, and self explanatory.

Architecture

Class based views

  • New with Django 1.3.
  • Nicer pattern for dealing with different request methods.
  • Because it's class based we can use all sorts of nice composition and inheritance to build behavior.

Old style:

def view(request):
    if request.method == 'GET':
        # do stuff
    elif request.method == 'PUT':
        # do other stuff

New style:

from django.views.generic import View

class MyView(View):
    def get(self, request):
        # do stuff

    def put(self, request):
        # do other stuff

Really simple

View classes composed of a few mixins:

  • Request Parsing
  • Response Rendering
  • Permissions & Authentication
  • Serialization (Request Validation & Response Filtering)

Request parsing

  • request.POST only provides for parsing form data...
  • ...and only for POST requests.

RequestMixin lets you write code like this:

class MyView(RequestMixin, View):
    parsers = (JSONParser,)

    def post(self, request):
        foo = self.DATA
        ...

Response rendering

  • HttpResponse objects are for rendered responses.
  • TemplateResponse does address this...
  • ...but assumes you'll always want to render the data using templates.

ResponseMixin lets you write code like this:

class MyView(ResponseMixin, View):
    renderers = (JSONRenderer, XMLRenderer)

    def get(self, request):
        ...
        if not exists:
            return Response(status.HTTP_404_NOT_FOUND, {'reason': 'whatever'})
        return {'foo': 'bar'}

Authentication & Permissions

  • Useful to be able to define these at a class level.

AuthMixin looks like this:

class MyView(AuthMixin, View):
    authentication = (BasicAuthentication, DigestAuthentication)
    permissions = (IsUserOrIsAnonReadOnly, )

    def get(self, request):
        # can always get here

    def put(self, request):
        # can only get here if we're authenticated

Serialization

  • Serialization in Django is limited.
  • Only for dumping QuerySets to fixtures.

ResourceMixin handles serializing objects to renderable data.

(And vice-versa)

class MyResource(ModelResource):
    model = MyModel
    fields = ('foo', 'bar', 'baz')

class MyView(ResourceMixin, RequestMixin, ResponseMixin, View):
    def get(self, request):
        ...
        return instance

    def put(self, request):
        foo = self.CONTENT
        ...

Pulling it all together

Default View class:

class MyView(View):
    form = MyForm

    def post(self request):
        stuff = self.CONTENT
        ...
        return other_stuff

Default ModelView classes:

class MyResource(ModelResource):
    model = MyModel

urlpatterns = patterns('',
    url(r'^$', ListOrCreateModelView.as_view(resource=MyResource)),
    url(r'^(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource=MyResource)),
)

Demo

Giving back to Django

  • Bug in HTTPRequest.read(). (Ticket #15785)
  • Work on customizable serialization.

The take home

  • Web API tooling is in it's infancy.
  • Web APIs should surely be Web browseable.
  • Let's push things forward!

Excited

Contribute!

  • Let's Sprint!
  • Fork us on Github or Bitbucket.
  • http://django-rest-framework.org
  • tom@tomchristie.com, @thisneonsoul