APIs are interfaces that let code written by other developers interact with your software – and interface code has to be designed for whoever is doing the interfacing.
When you (or someone else) designs a user interface that interface has to fit the user’s worldview, it has to work like the user expects it to work and it has to make things easy for the user – user interface that is designed to show how clever you are or the be as pure and theoretically correct as possible is hard for the outside user to understand, difficult to use and, in one word, sucks.
There’s nothing controversial about the last paragraph, I’m sure you had to use GUIs that are almost completely unusable (yet, probably make perfect sense to whoever created them).
When you (or someone else) designs an API that interface has to fit the other system’s developer’s worldview, it has to work like that developer expects it to work and it has to make things easy for the developer – API that is designed to show how clever you are or the be as pure and theoretically correct as possible is hard for the outside developer to understand, difficult to use and, in one word, sucks.
In other words, I don’t care how true your API is to the spirit of HTTP, I don’t care how object oriented it is – all I care is that it’s easy to use.
Here are some guidelines that will make your API easier to use (those are HTTP specific because, let’s face it, most APIS today are built on HTTP):
Be consistent in naming
If the endpoint for getting gallery details is GalleryGet than the endpoint to get image details should be ImageGet, not image_get and not GetImage.
Also, if you call a collection of images “gallery” always use the word “gallery”, don’t call it gallery in one place, album in another and folder in a third place.
Same go for parameter names, if the id of an image is called “imageId” then always call it “imageId” and not “idOfImage” or just “id”.
Use HTTP POST
There are just two HTTP verbs that are supported by every HTTP client library in existence (including badly written ones I must use on some project for some bad reasons) – GET and POST, I don’t care if you really think PUT or DELETE are better for some endpoints I have GET and POST.
For anything that accepts a complex data structure or a large amount of data you have no choice but to use POST.
For anything that changes the system or even remotely security related you should use POST because it makes cross site scripting attacks slightly harder.
For everything else also use POST so I don’t have to look up what request to make every single time I call your service.
Don’t get cute with HTTP status codes
For example, a failed login should not use code 404 (for user not found)
If the endpoint I’m calling doesn’t exist use status code 404, if the server is on fire (literally or metaphorically) you can use 500, otherwise use status code 200, also for errors.
Just about any http client treats success (200) and failure (anything else) differently, errors can raise exceptions or just cause a different code path to execute (the code path that handles things like no network connection, it’s not the code that should handle simple logic errors), don’t make my job harder, use status code 200 and return the error details in the HTTP content.
Don’t make me spread my logic all over the place because you know the complete list of HTTP status codes.
Note: obviously, it’s ok to return 401 as part of an authentication handshake, 304 if you use e-tags or other status codes that are explicitly required by the protocols you use – just don’t use HTTP status code for business logic errors.
The response should always have the same format
All service endpoints, in all success and failure modes should return data in the same format – and that format should be JSON, HTTP forms encoding or plain XML.
There are parsers and formatter for those 3 formats for just about every programing environment in existence.
Also, the response should always have some flag indicating success or failure at the same place – I want to be able to tell success from failure with generic code if needed (just put something like success:true or <status>fail</status> in there).
Note that this implies no empty response, if you don’t have any data to return just return the success flag, it makes it easier to see what happened in logs and debugging sessions.
And, for failures you should have an error code of some sort – and that brings us to…
No generic error please
I don’t really care if your error code is a number or a string – and accompanying it with a human radable error message is really nice.
But the important thing is to make the error specific and actionable:
“system error” means nothing, when a customer gets an error described as “system error”, “general error” or some other meaningless phrase I don’t have a clue where to start troubleshooting this.
“parameter error” is better, at least it points in a direction, “parameter error: invalid value for parameter id” is much better.
And the best error message is one that tells me what I did wrong and how to correct it, for example “parameter error, invalid value for parameter id, the id you passed is of a non-editable widget, please call EnableEditing before this call”, notice how that last error can be resolved in a minute while “general error” probably means hours of trying to find what the #%#! Went wrong
Or, the short version
Don’t make me waste time looking up unimportant details, make sure the API plays nice will all technology stacks (because you don’t know what crappy library I’ll have to work with) and set things up so they help we when things go wrong.