Skip to content

Instantly share code, notes, and snippets.

@shofetim
Created May 6, 2013 18:08
Show Gist options
  • Select an option

  • Save shofetim/5526906 to your computer and use it in GitHub Desktop.

Select an option

Save shofetim/5526906 to your computer and use it in GitHub Desktop.
"""
If this proves useful, move it to lib or something more suitable.
The intention is that we need a good API, one that can be used for
developing complex beehive UIs with backbone.js and that can be
exposed to customers.
(See wiki.aquameta.com/Letters_from_a_front-end_guy#5._Stuff_that_hearts_Backbone.js_and_iCanHaz,
there is abunch of stuff that is not yet spec'd)
We don't have anything good in place, but there are a few good options
available. We could use an existing API app / library. TastyPieAPI
tastypieapi.org, Django REST framework django-rest-framework.org
Django Piston bitbucket.org/jespern/django-piston/wiki/Home are the
leading ones. These, especially TastyPie, are nice. But they come with
a lot that we don't need: multiple formats, custom authentication,
etc. They also do not produce a standard JSON format that is
compatible with backbone.js or similar (JSON API jsonapi.org). We
could modify backbone sync (github.com/PaulUithol/backbone-tastypie or
do it ourselves) to work with Django's or the Django apps default data
representation. But that is just pushing the problem around, not
fixing it.
So we roll our own.
Lets use the existing cookie based auth and CSRF until and unless they
prove problematic.
Django forms don't look like the right way to handle input. They
expect urlencoded data by default, not JSON, their error message
generation doesn't really fit in the API responses, and they aren't
required for type coercion.
"""
#-----------------------------------------------------------------------------#
# The first challange is that Django's built in serializer doesn't
# produce compatible / reasonable JSON output. And that
# "serializers.serialize('json'" is abit verbose.
#
# The following serializes in Backbone.js / JSON API format, and is terse.
#-----------------------------------------------------------------------------#
from django.core import serializers
def to_json(queryset):
"""Creates a string that can be parsed as JSON from a queryset"""
return serializers.serialize("api", queryset)
def parse_json(data):
"""Parse JSON string into Python values"""
return json.loads(data)
#-----------------------------------------------------------------------------#
# Next we may want a class/mixin to help with the boilerplate
# GET/PUT/POST/DELETE pattern.
#-----------------------------------------------------------------------------#
class BaseView(object):
"""
BaseView provides a class that is instantiated and then
called like a function.
__init__ called without arguments.
You just (must) override the __call__ method.
"""
def __new__(cls, *args, **kwargs):
obj = super(BaseView, cls).__new__(cls)
return obj(*args, **kwargs)
def __call__(self, *args, **kwargs):
pass
from django.http import HttpResponse
class REST(BaseView):
"""
A class to handle CRUD boilerplate for Backbone.js requests.
Override methods as needed, be sure to set the model class in the child class.
"""
def __call__(self, request, *args, **kwargs):
func = self.getattr(self, request.method.lower(), "get")
return func(request, *args, **kwargs)
model_class = None #Override in child classes.
# HTTP methods www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
def get(request, *args, **kwargs):
if oid: #"object id" since id is a reserved word
data = self.model_class.objects.get(pk=oid)
else:
data = self.model_class.objects.all()
return HttpResponse(to_json(data), content_type="application/json")
def post(request, *args, **kwargs):
data = parse_json(request.body)
try:
obj = this.model_class(**data)
obj.save()
except Exception as e: #TODO
print e
print data
return HttpResponse(to_json(obj), content_type="application/json")
def put(request, *args, **kwargs):
data = parse_json(request.body)
obj = self.model_class.objects.get(pk=oid)
for field in data.keys:
setattr(obj, field = data[field])
obj.save()
return self.post(to_json(obj), *args, **kwargs)
def delete(request, *args, **kwargs):
obj = self.model_class.objects.get(pk=oid)
obj.delete()
return HttpResponse("", content_type="application/json")
def head(request, *args, **kwargs):
return self.get(request, *args, **kwargs)
def options(request, *args, **kwargs):
raise NotImplementedError
def trace(request, *args, **kwargs):
raise NotImplementedError
def connect(request, *args, **kwargs):
raise NotImplementedError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment