Letting you slack off while developing tasty APIs for Django apps.
This project is a fork of django-tastypie and the main aim is to refactor it in such a way, that the DRY principle will be respected. I mean - seriously - you shouldn't have to be forced to write any classes just to get a simple basic API functionality like listing your Models. Just like you don't have to write ModelAdmin classes to get your Admin Panel working.
The whole rationale behind this fork is outlined in Tastypie's issue #599.
Current version (v0.2.0) is considered beta - seems to work but needs heavy testing.
Warning
This project is NOT YET properly tested. Use at your own risk.
Any help and suggestions will be appreciated.
Note
All the rest of the documentation - for now - is a mirror of Tastypie's docs and as such is not 100% relevant to Biscuit. Expect corrections anytime soon. I'll accept any help to straighten this up.
- Python 2.6+
- Django 1.3+
- mimeparse 0.1.3+ (http://code.google.com/p/mimeparse/)
- Older versions will work, but their behavior on JSON/JSONP is a touch wonky.
- dateutil (https://launchpad.net/dateutil) == 1.5 (should also work with >= 2.1)
- python_digest (https://bitbucket.org/akoha/python-digest/)
- lxml (http://lxml.de/) if using the XML serializer
- pyyaml (http://pyyaml.org/) if using the YAML serializer
- biplist (http://explorapp.com/biplist/) if using the binary plist serializer
The most basic example looks like this:
# myapp/api.py
# ============
from biscuit.api import Api
from myapp.models import Entry
myapi = Api()
myapi.register(Entry)
# urls.py
# =======
from django.conf.urls.defaults import *
from myapp.api import myapi
urlpatterns = patterns('',
# The normal jazz here then...
(r'^api/', include(myapi.urls)),
)
That should get you a fully working, read-write API for the Entry
model that supports all CRUD operations in a RESTful way. Behind the scenes a ModelResource
is created with sane defaults based on the Model you registered. JSON/XML/YAML support is already there, and it's easy to add related data/authentication/caching. And all this without writing a single class.
There are other, better known API frameworks out there for Django. You need to assess the options available and decide for yourself. That said, here are some common reasons for biscuit.
- You need an API that is RESTful and uses HTTP well.
- You want to support deep relations.
- You DON'T want to be forced to write any classes to get basic functionality.
- You DON'T want to have to write your own serializer to make the output right.
- You want an API framework that is very flexible, doesn't push you around and maps well to the problem domain.
- You want/need XML serialization that is treated equally to JSON (and YAML is there too).
- You want to read only a short Tutorial to get started.
- Biscuit benefits from all API consumers tailored/optimized for Tastypie, like drest.
As the module has a different name, Biscuit itself is not a painless drop-in replacement for Tastypie as you'd need to refactor your code to get everything normally. But if you do want to benefit from some of Biscuit's goodness, you can checkout tastypie
branch. I try to keep it up to date with current Tastypie development plus it includes all the patches that do not break compatibility.
- You can register
Model
subclasses and appropriate ModelResource with sane defaults (meaningresource_name = <Model>._meta.module_name
andqueryset = <Model>.objects.all()
) is tailored behind the scenes. - You can register
Resource
subclasses (compare newv1.register(MyResource)
with oldv1.register(MyResource())
) - You can put all those in a list and write a single register:
v1.register([MyFirstResource, MyOtherResource]
). This list is not restricted and can contain bothResource
andModel
subclasses. - You can of course register
Resource
subclass' instances, just like you did in Tastypie (that's what "drop-in replacement" really means) No more cluttering urls.py - create
Api
instances in your app and then just import and include it in urls.py. Compare:# urls.py - Tastypie from tastypie.api import Api from myapp.api import FirstResource, SecondResource from otherapp.api import ThirdResource, FourthResource v1 = Api(api_name='v1') v1.register(FirstResource) v1.register(SecondResource) v1.register(ThirdResource) v1.register(FourthResource) urlpatterns = patterns('', # (...) url(r'^api/', include(v1.urls)), )
with:
# urls.py - Biscuit from biscuit import Api from myapp.api import myapi from otherapp.api import otherapi v1 = Api(name='v1', include=[myapi, otherapi]) urlpatterns = patterns('', # (...) url(r'^api/', include(v1.urls)), )
DRY and clean, isn't it? :)
Starting from 0.2.0 I'll try to follow Semantic Version guidelines.
Releases will be numbered with the following format:
<major>.<minor>.<patch>
And constructed with the following guidelines:
- Breaking backward compatibility bumps the major (and resets the minor and patch)
- New additions without breaking backward compatibility bumps the minor (and resets the patch)
- Bug fixes and misc changes bumps the patch
- Major version
0
means early development stage
For more information on SemVer, please visit http://semver.org/.
- Decouple
ModelResource
from specificModel
by extending logic ofApi.register()
if first argument is aModel
subclass, second should be aModelResource
that will wrap itself around theModel
. Optional argumentname
can be supplied to change the default resource name. - Extend the logic of
Api.register()
so that it would accept an additionalValidator
orForm
subclass that will be used to validate pushed data. InForm
caseregister()
should construct a sane defaultValidator
around it. This combined with previous feature allows for nice and clean registering of resources similar todjango.contrib.admin
approach. - Handle relationships by default - somehow