Building an API with Django and Django REST Framework
1. Building an API with Django and
Django REST Framework
PyTennessee 2016
2. 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. 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
7. 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. 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
11. 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!
14. 14
HTTP
• your basic HTTP request methods:
• POST
• GET
• PUT (and/or PATCH)
• DELETE
15. 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. 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. 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
20. 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. 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
23. 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
25. 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. 26
Generic Views
• basic GenericAPIView
• composable with mixins
• most common options pre-defined:
• ListCreateView
• RetrieveUpdateDestroyView
• others...
28. 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
30. 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. 31
URL Routing
• if you’re using ViewSets, do the following:
router = routers.DefaultRouter()
router.register(r'card', CardViewSet)
urlpatterns = router.urls
35. 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