Development with RESTful APIs enables organizations to integrate and thus more fully deliver on the promise of social, mobile, analytics and the cloud. In this tutorial we will provide a step-by-step guide to developing RESTful APIs.
REST is commonly identified with Roy Fielding’s 2000 PhD thesis, in which he first used the acronym REST (Representational State Transfer) and defined it as “a coordinated set of architectural constraints that attempts to minimize latency and network communication while at the same time maximizing the independence and scalability of component implementations.”
According to Fielding, REST is defined by four interface constraints:
- Identification of resources
- Manipulation of resources through representations
- Self-descriptive messages
- Hypermedia as the engine of application state
As far as we are concerned, this means that:
- Every interesting resource must have its own unique URI, which identifies the resource and can be used to request an instance of the resource. For example, http://pweb-14.appspot.com/videos/tutorial/ could identify the list of videos matching the query “tutorial.”
- Resources are manipulated using HTTP requests, usually through GET and POST methods, but PUT and DELETE might be more appropriate for some operations.
- Each identified resource can be returned in various formats (such as HTML, XML or JSON), and each of these formats is a representation of the identified resource; RESTful applications may support more than one representation of the same resource at the same URL, using the Accept HTTP header that is passed by the client to the server with each request for a resource. (The same goes for uploaded resources, using Content-Type HTTP header.)
- Communication must be state-less: Each client request and server response is a self-descriptive message—that is, each message contains all the information necessary to complete the task.
RESTful principles also provide strategies to handle CRUD actions using HTTP methods; an example mapping could be the following:
- GET /videos - Retrieves a list of videos (We won’t use this one because it wouldn’t make sense for our app.)
- GET /videos/tutorial - Retrieves the list of videos that match the keyword “tutorial”
- GET /videos/id/:id - Retrieves a specific video--in particular, the one whose id is :id
- POST /videos - Creates a new video on the server (We won’t implement this method in our API.)
- PUT /videos/:id - Updates video whose id is :id (We won’t implement this method in our API.)
- PATCH / videos/:id - Partially Updates video whose id is :id (We won’t implement this method in our API.)
- DELETE / videos/:id - Deletes the video whose id is :id (We won’t implement this method in our API.)
As you might have noticed, it is better to use the plural form, even when we retrieve/upload a single instance. This helps to avoid complicating the API: Think about the confusion that would be caused by odd plurals, or the bugs caused by mistakenly appending/not appending an “s” at the end of the URL!
Of the seven methods listed above, the first can’t be applied to our specific domain. (We can’t return a list of all the videos on YouTube, after all), while posting, updating and deleting videos would require OAuth authentication and are beyond the scope of this tutorial.
When choosing between the GET and POST methods, use this rule of thumb: Use POST when the action performed modifies the persistent data; use GET if--and only if--the action has no side effects. By default, crawlers (at least the “polite” ones) follow only GET methods. If you use GET, for instance, to delete an item from a list that can be accessed without authentication, you’ll end up with an empty list as soon as a search engine scans your website.
We can also take relations into account. For example, if we wanted to search videos matching certain keywords among those posted by a single user or having certain tags, we could use the following:
- GET /videos/tutorial/related/:id- Retrieves the list of videos that matches the keyword “tutorial” related to the video whose id is :id
- GET /videos/tutorial/regions/:region - Retrieves the list of videos for a particular country that match the keyword “tutorial”
And, of course, the same design can be applied to the other CRUD methods.
Finally, we need to consider filtering and sorting. It is best to avoid retrieving the complete list of results for a query. (Sometimes we are even prevented from doing so, such as with the YouTube Data API.) To apply a cap on the number of results retrieved, sorting criteria become very relevant.
It’s always important to remember that simple means usable, and keeping it simple is almost always better when it comes to APIs.
To keep our API as simple as possible, implement filtering and sorting with query parameters in the URL:
- GET /videos/tutorial?max_results=10&first_result=6 - Retrieves (at most) 10 videos that match the keyword “tutorial” starting from the sixth result
- GET /videos/tutorial?max_results=5&sort=rating - Retrieves the first five videos that match the keyword “tutorial,” with results sorted by users’ ratings