Before I jump directly into my version of "Donny Do" and "Donny Don't" for APIs, I'll give a bit of background as to the steps I took to develop our API.
(**Note: **If you get REST and how to structure a REST API, skip this post).
When I was asked to design our API my first step was to watch Teach a Dog to REST. Then watch it again, and again. I made other members of the team watch it, and took as much as I could from it.
This video is probably the most elegant demonstration I've seen that articulates "proper" REST API design.
From here I took my instructions from the video and broke down the application into its different types of resources.
As the application I was dealing with was to do with SMS messaging, the resources became things like messages, message templates, recipients, and recipient groups.
I didn't start with the use cases, e.g. "how do I send a message" because identifying the resources and the resource types within the API is far more important at this stage than worrying about what you can do with the API.
The reason is that if you focus on the use cases (the verbs) you'll end up with a list of actions. This may sound OK, but ultimately this path will lead to a bunch of action based URLs e.g. /sendMessage, /createRecipient or (worse) /addRecipientToDistributionList.
Focus on the resources (the nouns) instead. What you actually want at this stage is simply the list of resource group URLs:
From here I simply thought of each of the main 4 HTTP verbs acting on my URLs; POST, GET, PUT and DELETE (Create, Read, Update and Delete respectively).
|messages||Retrieve a listing of messages.||Create and send a new message||Not Implemented||Not Implemented (could refer to deleting all messages)|
|message templates||Retrieve a listing of message templates||Create a new message template||Not Implemented||Not Implemented (could refer to deleting all templates)|
|recipients||Retrieve a listing of recipients.||Create a new recipient||Not Implemented||Not Implemented (could refer to deleting all recipients)|
|recipient groups||Retrieve a listing of recipient groups.||Create a new recipient group||Not Implemented||Not Implemented (could refer to deleting all groups)|
Note: we still haven't gotten into any schemas or technical implementation details. During this phase I am trying to define a simple API structure; that's it. After completing the table for the resource groupings, I then moved on to each individual resource.
|messages/[ID]||Retrieve an individual message||Not Implemented||Update an individual message (possibly relevant for drafting)||Delete an individual message|
|messagetemplates/[ID]||Retrieve a message template||Not Implemented||Update an individual message template||Delete an individual message template|
|recipients/[ID]||Retrieve a recipient record||Not Implemented||Update an individual recipient record||Delete an individual recipient record|
|recipientgroups/[ID]||Retrieve a recipient group||Not Implemented||Update a recipient group's details, or add a recipient to the group.||Delete a recipient group|
Structuring my table like this forced me to think about what each action is going to perform as I only had 4 actions to work with (there are a few others but we'll get to them later).
For example, I made the call that when you performed a POST to /messages this would not only Create the Message, it would also Send it.
Some would argue that the resource should have been created in one step, and sent in another e.g. create it with a POST to /messages, then update it with a PUT to move it to a 'sent' state.
This was an option I considered, but I decided that more of my users would be sending messages in one single step than there were those that would require a draft/send process, so I went with the two in one approach.
When you are designing your API, I would encourage you to start here also. It will take some time to map out what each resource is, and what the 4 verbs mean for each, but it will be worthwhile in the long run.
Originally published on jordwalsh.com - 24 April 2014