Creating a basic API with Django

11 August 2008

Creating a simple public API for your site is a lot easier than you may think with Django. You’re basically just creating another view and serving it as XML or JSON instead of HTML.

Step 1) What’s public?

Decide what you want to be public. The best answer is the stuff you’re already displaying in your HTML templates. Then you need to create an entry in your url conf.

url(r'^api/v1/(?P<username>[-\w]+)/notes/?$', 'readernaut.api.views.user_notes'),

Step 2) Create the view.

In the case for Readernaut I wanted to provide an XML feed for users notes. Here is what the view looks like:

def user_notes(request, username):
    reader = get_object_or_404(User, username__iexact=username)
    note_list = Note.objects.filter(user=reader)
    context = { 'reader': reader, 'note_list': note_list }
    return render_to_response('api/note_list.html', context, context_instance=RequestContext(request), mimetype='application/xml')

This is a simplified version of the view but, as you can see, you could easily add pagination and other hooks to handle ordering and such.

Step 3) Create the template.

The view is pointing to the template api/note_list.html so all we need to do is create that file and build out our XML schema.

<?xml version="1.0" encoding="utf-8"?>
<notes version="1.0">
    {% for note in note_list %}
    <note>
        <note_id>{{ note.id }}</note_id>
            <user>
            <username>{{ note.user }}</username>
        </user>
        <book_edtion>
            <title>{{ note.book_edition }}</title>
            <isbn>{{ note.book_edition.isbn }}</isbn>
        </book_edtion>
        <body><![CDATA[{{ note.note }}]]></body>
        <page_reference>{{ note.page_reference }}</page_reference>
        <created>{{ note.created|date:"Y-m-d G:i T" }}</created>
        <modified>{{ note.modified|date:"Y-m-d G:i T" }}</modified>
    </note>
    {% endfor %}
</notes>

How you define your XML templates is up to you. I name my templates with the .html extention simply because my text editor highlights the syntax better than if it were XML. It doesn’t matter because the mimetype dictates how the file is served up. Good luck!

Comments

Brian Mckinney http://brianmckinney.net

Creating APIs with Django is something I’ve been curious about for a while, though I haven’t noticed many people talking about it. Thanks for posting a good starting point in that direction. I’m continually surprised by how flexible Django can be, and how easy it is to pull something like this off so quickly.

Jeff Croft http://jeffcroft.com

Great post. Nice to see how simple it is, and nice to see you’re just really doing the same thing you’d do to create a simple HTML view. I’m curious: what are the pros and cons of using a template, as you have done, versus using Django’s serialization? Off the top of my head, I guess the big trade off is complete control over the format of your XML or JSON (using a template) versus not having to worry about your XML or JSON being valid (as the serialize method should take care of that for you, right?).

Just curious what you (or anyone else) though.

Beshr Kayali http://beshrkayali.com

Very nice post! Thanks!

Henrik Lied http://henriklied.no

For extensibility, I would believe that this method from Alberto Garciá Hierro is more flexible: http://fi.am/entry/building-a-website-api-with-django-par…

Rémi Prévost http://remiprevost.com

Cool, I didn’t know there was a “render_to_response” shortcut!

Matt Croydon http://postneo.com

I would have probably used the serialization framework instead of templating it out, but it’s hard to beat how quick it is to generate an XML feed this way.

I totally did the same thing last week to create an XML feed for broadcast election coverage.

Daniel Lindsley http://www.snow-wolf.net/

@Jeff Croft - From my understanding, the serialization aspects of the framework serialize Django object sets (usually a QuerySet) so it can be somewhat limiting as to is actually serialized. Easy and valid. Nathan’s method, on the other hand, let’s him present whatever data he wants, even if the data is not related in the database as well as custom data he might want to introduce that isn’t even a Django object, like a status message or custom computed values like a sum/average/total.

Nathan Borror http://www.playgroundblues.com

Yeah, I was really going for full control over the XML schema and the only way to achieve it was using the template system. I plan to do the same with a JSON version.

The biggest danger seems to be making a syntax error but with proper validation tools this can be mitigated.

yashh http://www.yashh.com

Awesome. I was exactly looking for something like this. How does the authentication work over the API?

Nathan Borror http://www.playgroundblues.com

@yashh - This is an example of a simple public API and wouldn’t work well for a private API. I recommend checking out http://code.google.com/p/django-rest-interface/

kevin http://blog.howiworkdaily.com

very creative solution nathan.

Brian Rosner http://oebfare.com

For a simple private API check out http://code.google.com/p/django-notification/source/brows…. Decorate the view and viola authenticated API access. Tweaking may be required :)

John Williams http://internetmp3.org/artist3105/John-Williams-discography/

Pretty nice site, wants to see much more on it! :)

john

cool post. thanks.