<p>This tutorial will cover creating a simple pastebin code highlighting Web API. Along the way it will introduce the various components that make up REST framework, and give you a comprehensive understanding of how everything fits together.</p>
<p>The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the <ahref="../quickstart">quickstart</a> documentation instead.</p>
<hr/>
<p><strong>Note</strong>: The code for this tutorial is available in the <ahref="https://github.com/tomchristie/rest-framework-tutorial">tomchristie/rest-framework-tutorial</a> repository on GitHub. The completed implementation is also online as a sandbox version for testing, <ahref="http://restframework.herokuapp.com/">available here</a>.</p>
<hr/>
<h2id="setting-up-a-new-environment">Setting up a new environment</h2>
<p>Before we do anything else we'll create a new virtual environment, using <ahref="http://www.virtualenv.org/en/latest/index.html">virtualenv</a>. This will make sure our package configuration is kept nicely isolated from any other projects we're working on.</p>
<pre><code>:::bash
virtualenv env
source env/bin/activate
</code></pre>
<p>Now that we're inside a virtualenv environment, we can install our package requirements.</p>
<pre><code>pip install django
pip install djangorestframework
pip install pygments # We'll be using this for the code highlighting
</code></pre>
<p><strong>Note:</strong> To exit the virtualenv environment at any time, just type <code>deactivate</code>. For more information see the <ahref="http://www.virtualenv.org/en/latest/index.html">virtualenv documentation</a>.</p>
<h2id="getting-started">Getting started</h2>
<p>Okay, we're ready to get coding.
To get started, let's create a new project to work with.</p>
<pre><code>cd ~
django-admin.py startproject tutorial
cd tutorial
</code></pre>
<p>Once that's done we can create an app that we'll use to create a simple Web API.</p>
<pre><code>python manage.py startapp snippets
</code></pre>
<p>We'll need to add our new <code>snippets</code> app and the <code>rest_framework</code> app to <code>INSTALLED_APPS</code>. Let's edit the <code>tutorial/settings.py</code> file:</p>
<pre><code>INSTALLED_APPS = (
...
'rest_framework',
'snippets',
)
</code></pre>
<p>We also need to wire up the root urlconf, in the <code>tutorial/urls.py</code> file, to include our snippet app's URLs.</p>
<pre><code>urlpatterns = [
url(r'^', include('snippets.urls')),
]
</code></pre>
<p>Okay, we're ready to roll.</p>
<h2id="creating-a-model-to-work-with">Creating a model to work with</h2>
<p>For the purposes of this tutorial we're going to start by creating a simple <code>Snippet</code> model that is used to store code snippets. Go ahead and edit the <code>snippets/models.py</code> file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself.</p>
<pre><code>from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES,
default='python',
max_length=100)
style = models.CharField(choices=STYLE_CHOICES,
default='friendly',
max_length=100)
class Meta:
ordering = ('created',)
</code></pre>
<p>We'll also need to create an initial migration for our snippet model, and sync the database for the first time.</p>
<h2id="creating-a-serializer-class">Creating a Serializer class</h2>
<p>The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such as <code>json</code>. We can do this by declaring serializers that work very similar to Django's forms. Create a file in the <code>snippets</code> directory named <code>serializers.py</code> and add the following.</p>
<pre><code>from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
<p>The first part of the serializer class defines the fields that get serialized/deserialized. The <code>create()</code> and <code>update()</code> methods define how fully fledged instances are created or modified when calling <code>serializer.save()</code></p>
<p>A serializer class is very similar to a Django <code>Form</code> class, and includes similar validation flags on the various fields, such as <code>required</code>, <code>max_length</code> and <code>default</code>.</p>
<p>The field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The <code>style={'type': 'textarea'}</code> flag above is equivelent to using <code>widget=widgets.Textarea</code> on a Django <code>Form</code> class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial.</p>
<p>We can actually also save ourselves some time by using the <code>ModelSerializer</code> class, as we'll see later, but for now we'll keep our serializer definition explicit.</p>
<h2id="working-with-serializers">Working with Serializers</h2>
<p>Before we go any further we'll familiarize ourselves with using our new Serializer class. Let's drop into the Django shell.</p>
<pre><code>python manage.py shell
</code></pre>
<p>Okay, once we've got a few imports out of the way, let's create a couple of code snippets to work with.</p>
<pre><code>from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
snippet = Snippet(code='foo = "bar"\n')
snippet.save()
snippet = Snippet(code='print "hello, world"\n')
snippet.save()
</code></pre>
<p>We've now got a few snippet instances to play with. Let's take a look at serializing one of those instances.</p>
<p>At this point we've translated the model instance into Python native datatypes. To finalize the serialization process we render the data into <code>json</code>.</p>
<p>Notice how similar the API is to working with forms. The similarity should become even more apparent when we start writing views that use our serializer.</p>
<p>We can also serialize querysets instead of model instances. To do so we simply add a <code>many=True</code> flag to the serializer arguments.</p>
<p>Our <code>SnippetSerializer</code> class is replicating a lot of information that's also contained in the <code>Snippet</code> model. It would be nice if we could keep our code a bit more concise.</p>
<p>In the same way that Django provides both <code>Form</code> classes and <code>ModelForm</code> classes, REST framework includes both <code>Serializer</code> classes, and <code>ModelSerializer</code> classes.</p>
<p>Let's look at refactoring our serializer using the <code>ModelSerializer</code> class.
Open the file <code>snippets/serializers.py</code> again, and edit the <code>SnippetSerializer</code> class.</p>
<p>One nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing it's representation. Open the Django shell with <code>python manange.py shell</code>, then try the following:</p>
<p>It's important to remember that <code>ModelSerializer</code> classes don't do anything particularly magical, they are simply a shortcut for creating serializer classes:</p>
<p>Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as <code>csrf_exempt</code>. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.</p>
<p>We'll also need a view which corresponds to an individual snippet, and can be used to retrieve, update or delete the snippet.</p>
<p>It's worth noting that there are a couple of edge cases we're not dealing with properly at the moment. If we send malformed <code>json</code>, or if a request is made with a method that the view doesn't handle, then we'll end up with a 500 "server error" response. Still, this'll do for now.</p>
<h2id="testing-our-first-attempt-at-a-web-api">Testing our first attempt at a Web API</h2>
<p>Now we can start up a sample server that serves our snippets.</p>
<p>Quit out of the shell...</p>
<pre><code>quit()
</code></pre>
<p>...and start up Django's development server.</p>
<pre><code>python manage.py runserver
Validating models...
0 errors found
Django version 1.4.3, using settings 'tutorial.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
</code></pre>
<p>In another terminal window, we can test the server.</p>
<p>Similarly, you can have the same json displayed by visiting these URLs in a web browser.</p>
<h2id="where-are-we-now">Where are we now</h2>
<p>We're doing okay so far, we've got a serialization API that feels pretty similar to Django's Forms API, and some regular Django views.</p>
<p>Our API views don't do anything particularly special at the moment, beyond serving <code>json</code> responses, and there are some error handling edge cases we'd still like to clean up, but it's a functioning Web API.</p>
<p>We'll see how we can start to improve things in <ahref="../2-requests-and-responses">part 2 of the tutorial</a>.</p>