In part one of our tutorial, we’ll be creating a ResourceModel to interact with a simple Tastypie Django site. Tastypie is a third party Django app that makes creating to-spec REST APIs. Because of this, it’s the perfect match to write our first ResourceModel, as it will require only a little fine tuning.
Let’s start by writing a very basic ResourceModel and going through it’s parts:
from nap import ResourceModel, Field, ResourceField class Note(ResourceModel): title = Field(default='new title') content = Field() pk = Field(api_name='id', resource_id=True) class Meta: root_url = 'http://127.0.0.1:8000/api/v1/' resource_name = 'note'
We have a few things to note here:
Two normal Fields, title and content. On any lookup field nap does, these will simple load whatever value the API returns for attributes with the same names. If the fields are not present, the Note object will be loaded with their default value (a blank string by default, or ‘new title’ in the case of title)
That’s quite a lot! Feel free to quick through the in-links above to find out more about each option, but there’s no need to dive in too deeply yet.
Our API is empty right now (assuming you haven’t added data manually), so let’s add a new Note:
>>> n = Note(title="A New Note!") >>> n.content = "Daniel Lindsley rocks da house" >>> n.save()
There! We’ve now created our first object in our API, and can retrieve it by it’s id:
>>> n = Note(pk=1) >>> print n.title # "A New Note!"
Remember, since we used api_name on the pk Field in our ResourceModel definition, we use pk to look up a value that the API refers to as id
We can also update and save this resource:
>>> n.title = "Let's use a new title" >>> n.save()
And a PUT is issues to our API, updating our record.
Note that we had to re-fetch our Note in order to properly have access to it’s pk attribute. When we issued the create command, we weren’t able to update our Note with information calculated by the API itself (such as it’s ID, and created/updated timestamps). If we need to make many of these kind of creates and don’t mind the cost of an extra request, refreshing the object after a create may be beneficial. Our next step will go into a few ways we can handle that.
By default, Tastypie APIs respond to a POST request with 201 response with a Location header pointing to the new resource’s URL. By default, nap will automatically set the value of the Location header as the Note object’s full_url, so any further updates should work. However, because Tastypie by default does not return a serialized representation of the object, we can’t get updated information without issuing a second GET request.
There are several ways we could address this:
Not only does this sound like the best method, it also gives us an excuse to show how easy it is to extend ResourceModel.
from nap import ResourceModel, Field, ResourceField class Note(ResourceModel): title = Field(default='new title') content = Field() pk = Field(api_name='id', resource_id=True) class Meta: root_url = 'http://127.0.0.1:8000/api/v1/' resource_name = 'note' def handle_create_response(self, response): super(Note, self).handle_create_response(response) if not response.content: self.refresh()
We call the parent handle_create_response to let it handle the default behavior (eg, setting of full_url), then if we don’t have any content to go off of, refresh the object. Now our create process is seemless:
>>> n = Note(title='what up') >>> n.save() # Issues a POST to /api/v1/note/ >>> print n.pk # 6 >>> n.content = 'some content' >>> n.save() # Issues a PUT to /api/v1/note/6/
And there we have it! A feature-full interface to our REST API.
In the next step, We’ll go into handling a REST-like, but slightly off spec, REST API with some further tweaks.