Building an API with Django and Django REST Framework
PyTennessee 2016
2
Hi, I’m Chris Foresman
• Senior Systems Engineer at Vokal• Python mentor to all ages• Learned to program in BASIC on a
TRS-80 circa 1986• Love: karaoke, bourbon, brunch• I have a 3-yr-old at home
@foresmac
3
Hi, I’m Adam Bain
• Systems Engineer at Vokal• Rehabilitated Java engineer via
Python• Learned to program in BASIC circa
94• Likes: Hockey, Craft Beer• I referee robotics competitions
@adam_bain
4
Let’s build an API!
5
With Python!
6
Who’s with us so far?
7
If you want to follow along:
• terminal access• a text editor: SublimeText, Atom, vim• or IDE, like PyCharm• ideally have virtualenv (or venv)• git
8
If you want to follow along:
• mkdir ~/tutorial• virtualenv ~/tutorial• cd ~/tutorial• source bin/activate• pip install django djangorestframework• git clone https://github.com/vokal/deckbuilder-api.git• git checkout -b base base
9
Ok, let’s get started.
10
Planning
11
Planning
• sketch out your data models• how will different things be represented?• think about what actions your API needs to support• will you be strictly RESTful, supporting only CRUD?• or, will your API be more expressive?• it’s up to you to strike a balance!
12
Wait, isn’t CRUD bad? And why do I need REST already?
13
CRUD
• your basic database operations:• CREATE• READ• UPDATE• DELETE
14
HTTP
• your basic HTTP request methods:• POST• GET• PUT (and/or PATCH)• DELETE
15
REST in a nutshell
• your basic RESTful API:• CREATE = POST• READ = GET• UPDATE = PUT (and/or PATCH)• DELETE = DELETE
FYI: REST stands for Representational State Transfer
16
Common RESTful pattern
• /object• POST data to this endpoint to create a new object• GET this endpoint to retrieve a list of objects
• /object/:id• GET this endpoint to get details about a particular object• PUT or PATCH data to this endpoint to update that object • DELETE this endpoint to delete the object
17
Pragmatic, not-strictly-RESTful patterns
• /object/:id/action• Either POST data to this endpoint to perform some action,
particularly if it results in new data being created, or• PUT to this endpoint to perform some action that doesn’t require
any additional data, and typically modifies existing data but does not create new data objects
• /object/noun• GET this endpoint to get some specific grouping or set of the
objects
18
Be as logically consistent as humanly possible
19
Models
git checkout -b models models
20
Models
• define objects that represent your data• map fields to database column types• handle DB magic for you (for the most part)• strive for “fat” models and “thin” views
• give your models methods• for complicated creation, updating, etc, use managers
21
Models
• know your field types• CharField• IntegerField• BooleanField• DatetimeField• etc
• fields also have parameters that affect database table creation and data validation• null=True, max_length=255, etc
22
Serializers
git checkout -b serializers serializers
23
Serializers
• this is the main gateway between your API and the world• typically:
• validates input• converts JSON to Python dict• converts model instances to Python dicts
• which can then be passed to model instances and saved to the database
24
Generic Views
git checkout -b generic_view generic_view
25
Generic Views
• class-based views• can be configured with basic attributes:
• serializer• permissions_classes• queryset
• or can use more dynamic config:• get_queryset()• get_serializer()• etc
26
Generic Views
• basic GenericAPIView• composable with mixins• most common options pre-defined:
• ListCreateView• RetrieveUpdateDestroyView• others...
27
View Sets
git checkout -b view_set view_set
28
View Sets
• great for straightforward CRUD operations• can be extended with additional “detail” views• automagically handle URL routing generation• a lot of functionality for a little bit of code
29
URL Routing
30
URL Routing
• just match a URL regex with a corresponding view• call as_view() on it, like so:
url(r’^/card/?$’, ListCreateCardView.as_view(), name=’list-create-card’)
31
URL Routing
• if you’re using ViewSets, do the following:
router = routers.DefaultRouter()router.register(r'card', CardViewSet)urlpatterns = router.urls
32
“Browsable” API
git checkout -b browsable_api browsable_api
33
“Browseable” API
• Let’s you experiment with your API via a browser
34
Testing
35
Testing
• why does everyone hate it?• trust us, you’ll thank yourself later• generally “integration” tests cover most code• additional unit tests cover everything else• for Pete’s sake, learn to use mock
36
You’ve got questions?
37
We’ve got answers.
38
(Hopefully)
39
Resources
• http://www.django-rest-framework.org• https://docs.djangoproject.com• https://virtualenv.readthedocs.org• https://github.com/vokal/deckbuilder-api
Thank you!
PyTennessee 2016