I posted a few days ago about my ideas for 11 rules for practical API development. Let’s jump back in with rules 6 to 11.
6. Make it easy to understand and navigate through child objects. The fact is it can be really easy to confuse your database fields as API fields. You might have a field in your table called color_id that represents a color in the color table. Your service returns color_id and you expect your users to somehow know to hit the color service to find out more information about the color. It will behoove you to represent the color as an object since it is an attached object. Also, including a URL where the user can get more information about the color is super helpful. And if you have an extra minute, throw in the URL where they can see all the colors in the meta part of your response. For example: {…”color” : {“id” 3, “name” : “blue”}…}{“meta” : {“urls” : [{“color” : “http://yourcoolapi.com/color/”}]}}. Use a convention like that and developers will be able to add code to automatically pull in more information about the object as well as pull all objects for a picker list.
7. Allow users to limit which fields they receive. If a user wants to only grab the id and name of 300 objects, why make them retrieve all of the fields on each object? It is a lot of data for them, a lot for you, and it just makes everything slow. Maybe this breaks the rules, but it will save everyone so much time and resources.
8. Allow users to modify and access child objects directly. (Confession: As a developer, I rarely implement this.) If you have a hierarchy like menu->courses->dishes, your users should be able to add/update/remove dishes from a specific course without sending the entire course or menu object. Usually this is done by allowing people to POST to a URL like menu/7/course/1/dish to add a dish to the menu with id 7 and course with id 1. Updating a dish can be done via put and removing via DELETE to a URL like menu/7/course/1/dish/13.
9. Enable versioning. I don’t care if it is in the URL or the header – just allow people to hit a specific version. This way, you can make improvements without breaking old APIs. I’m very fond of the format: yourfavoriteapi.com/v1.1/service. I know some people say putting the version in the URL breaks REST and kills kittens, but oh well. It’s so easy to implement and to consume. Most users who implement your API will have the base URL as some sort of static of config variable, so including the version in the base URL makes it super easy. Foursquare does this cool thing where you pass in the date in which you are working on your code. They can then cross reference that against release dates and figure out which API version you are using. It is a pretty cute solution for users having to increment versions since version numbers don’t make sense to users and users will typically upgrade to whichever the most recent version is. Though for me, I think I will stick with version numbers.
10. Feel free to break the rules of the URL every now and then. Some people are completely against passing GET parameters to your services. They say you should somehow pass pagination requests through the headers. I personally feel that if you are doing some sort of filtering on a data set, feel free to pass those parameters in the GET – pagination, sorting, etc. And while you are at it, feel free to throw in the format of the data (json, xml, etc.). I know people are saying “HAI you cannot put .xml at the end of the service request! That makes it look like a different object! Put it in the content types that you accept!” That’s cute and all, but you can have multiple representations of the same item in different file formats. Imagine downloading a logo that comes in PNG and GIF form. Is it that crazy for identical images to have the same file name but different extensions? No, it is fine. Don’t over-think things.
11. Include pagination links on GET. As your API grows, you will want to paginate results. Come up with a scheme of how that works, but don’t expect the user to all of a sudden know when a service needs pagination or how to build the URL for the next set of data. Include URLs for the next and previous set of data. Now users can write generic wrappers and if they see that next, they can keep iterating through until they have all of their data. Easy peasy.