Interface • Building an API lets people write applications that use your technology • Web APIs are collections of URLs pointing to service or data locations
to it won’t change REST in 10 seconds • Uses HTTP concepts with standardized Create Read Update Delete headers. POST, GET, PUT, DELETE • POSTing data? A new record will be created, keeping existing records safe • DELETE only what you mean to DELETE
Procedure Call APIs don’t enforce a relationship between the request and the data • No correlation between URL and DB record • Misusing GET can create massive security holes GET /api/photo/uploads/1 ? POST /api/photo/uploader/ ?
with data, you probably don’t want to store every result. • POST requests are good at sending complex parameters • Millions of POSTs, no new DB data? Not very REST-friendly. json_data = { data: [‘that’, ‘does’, ‘not’, ‘fit’, ‘keywords’] }
= models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True, editable=False) image = models.ImageField(upload_to='static/photos/' + uuid.uuid4().__str__() +'/') average_color = models.CharField(max_length=6) # average_color e.g. ‘FF2437’ How do you turn this into an API? I used Tastypie.
PhotoResource photo_resource = PhotoResource() urlpatterns = patterns('', # Examples: url(r'^browse', 'viewer.views.browse'), url(r'^upload', 'viewer.views.upload'), url(r'^api/', include(photo_resource.urls)) # ... other routes in your app can go # into this definition, if you like )
lets you create custom URLs. • Redefine prepend_urls on the Resource. • Point the custom URL to a helper that calls a utility method elsewhere. • The helper should return self.create_response(request, obj)
class PhotoResource(ModelResource): # class Meta defined as before def find_average_color(self, request, **kwargs): self.method_check(request, allowed=['post']) response = {} if request.body: params = json.loads(request.body) average_colors = Photo.objects.filter(pk__in=params['photo_ids']).values_list('average_color', flat=True) # Some terribly clever calculation to find the average color. response['average_color'] = average_colors[0] self.create_response(request, response) def prepend_urls(self): return [ url(r"^(?P<resource_name>%s)/find_average_color%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('find_average_color'), name="api_find_average_color"), ]