In "5 Best Practices for Better RESTful API Development," we discussed our top best practices for API design including tips for using associations and error formatting. Today, we're discussing versioning, partial responses, pagination, multiple formats, and responses in the second part of this article series.
Versioning can be done in a few different ways. Here's an example where the version number has been inserted into the URL:
One benefit to this approach is that it makes sure that the version isn't optional and has to be included in the URL. As a result, you'll only need to make a change to the version number when moving to a new version. However, using a decimal point in your URL structure isn't a good idea. It's better to keep the versions as integral as possible. Instead, keep to whole numbers for versioning.
The following example shows the version number in the form of a timestamp:
One on hand, this versioning format is great because the timestamp is unique and incorporated into the URL. On the other hand, it's a little too complicated. Versions aren't supposed to change too frequently.
Here's another example that's very intuitive and readable:
In this case, however, version is optional, which creates a problem when moving to a new version.
Should the version be included in the URL or the header? Personally, I'm in favor of putting the version in the header rather than the URL. How might you do that? Here are three different examples:
Accept-Datetime: Thu, 1 Oct 2013 20:35:00 GMT Cookie: $Version=1; Skin=new; ETag: "737060cd8c284d8af7ad3082f209582d"
2. Partial Responses
The era of returning complete objects is gone. In the mobile world, it makes sense to only request the data that we need. As a result, the URL should be designed in a way that allows the user to request partial responses. However, the fields parameter should be an optional as we don’t expect the user to request the necessary fields explicitly with every single request. Here are two examples that show how to implement partial responses in your URL:
I personally recommend the example that includes the optional fields parameter to keep it simple. In the URL is especially complex, then we can always use the a colon in the URL structure.
We all know that there's a need for pagination. We can’t return thousands or hundreds of records when it comes to fast and responsive UIs. Pagination is a necessity. Here are three different examples to account for pagination within your URL:
chanderdhall.com/podcasts?offset=3&limit=5 chanderdhall.com/podcasts?page=3&rpp=5 chanderdhall.com/podcasts?start=3&count=5
The difference in these examples is the naming convention. I personally recommend using offset and limit because it's the industry standard. It’s evident that the API is asking for podcasts, which have an offset of 3 and limit of 5. In other words, we're seeking records 4 through 8 from the database.
At the same time, default pagination should always be included. This can vary depending on your application. However, I’d recommend keeping it consistent as possible.
4. Multiple Formats
The API should be capable of supporting multiple formats. However, I recommend using the Accept header rather than specifying the format in the URL. There are several APIs that use one of these two approaches:
a. chanderdhall.com/podcasts?type=json Or chanderdhall.com/podcasts?type=xml b. chanderdhall.com/podcasts.json Or chanderdhall.com/podcasts.xml
I like the second approach out of these two examples. However, I'm not a big fan of specifying the format in the URL. Here's my recommended approach:
chanderdhall.com/podcasts accept: application/json
Content negotiation is important, and the API should handle every single scenario possible. However, when it comes to the default format, I’d recommend JSON.
a. "Created_At": "2013-10-10T04:35:00Z" b. "DateTime": "2013-10-10T04:35:00Z"
var podcast = JSON.parse(response);
In this case, the developer expects to be using podcast.createdAt or podcast.datetime instead of podcast.DateTime or podcast.Created_At.
Again, it's perfectly okay to use camel casing based on the type of object returned. Please feel free to visit my blog for related articles.