Building Apis With Django Rest Framework: Timothy Liu, VP Engineering
Building Apis With Django Rest Framework: Timothy Liu, VP Engineering
Response
Check Obj. Perms
Paginate Data
Serialize
Response
REST: HTTP request and response (w/ JSON)
{
"id": 123
}
REST: Resources
"https://api.server.com/v1/accounts"
*URLs in urlpatterns can also route to DRF views directly, similar to in Django
REST: Resources
"https://api.server.com/v1/accounts"
.list()
GET .retrieve()
POST .create()
PUT .update()
PATCH .partial_update()
DELETE .destroy()
READ requests ViewSets: Class-based Views
● Routers map to actions. Defaults available for Django models.
class AccountViewSet(viewsets.ViewSet):
"""A simple ViewSet for listing or retrieving Accounts."""
django-rest-framework.org/api-guide/viewsets
READ requests ViewSets: Using QuerySets
Filter QuerySet ● Query the database.
class IsOwnerFilterBackend(filters.BaseFilterBackend):
"""Filter that only allows users to see their own objects."""
def filter_queryset(self, request, queryset, view):
return queryset.filter(owner=request.user)
class AccountViewSet(viewsets.ModelViewSet):
"""A simple ViewSet for searching owned accounts: GET /accounts?email=kloudless"""
queryset = Account.objects.all()
serializer = AccountSerializer
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'name', 'custom_properties']
class CustomPagination(pagination.PageNumberPagination):
def get_paginated_response(self, data):
return Response({
'links': {
'next': self.get_next_link(),
'previous': self.get_previous_link()
},
'count': self.page.paginator.count,
'results': data
})
class AccountViewSet(viewsets.ModelViewSet):
pagination_class = CustomPagination
REST: HTTP request and response (w/
Authentication
JSON)
Check
Permissions
Rate-limiting
class TokenAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
token = authentication.get_authorization_header(request).partition(' ')[-1]
try:
user = User.objects.get(token__key=token)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
class IsOwnerForModification(permissions.BasePermission):
"""Only allow write access to the object's owner"""
def has_object_permission(self, request, view, obj):
# GET, HEAD, OPTIONS allowed
if request.method in permissions.SAFE_METHODS:
return True
django-rest-framework.org/api-guide/permissions
Authentication Rate-limiting User Requests
Check ● Per-user throttles: Burst (e.g. 10/s), Sustained (e.g. 10,000/day)
Permissions
● Can be scoped per View, or include custom throttling like below.
Rate-limiting
class CosmicRayRateThrottle(throttling.BaseThrottle):
"""Simulate a stray cosmic ray flipping a bit that rate-limits this request"""
def allow_request(self, request, view):
return random.randint(1, 10e12) == 1
django-rest-framework.org/api-guide/throttling
READ requests
Advanced Concepts
Filter QuerySet
Response
Check Obj. Perms
Paginate Data
Serialize
Response
Custom Endpoints and QuerySets
● DRF allows custom routes and view methods
class KloudlessFileQuerySet(object):
def copy(self, *args, **kwargs):
... # copy file in cloud service
class CustomFileViewSet(viewsets.ViewSet):
queryset = KloudlessFileQuerySet()
@action(detail=True, methods=['post'])
def copy(self, request):
queryset = self.filter_queryset(self.get_queryset())