Most mobile and distributed applications have an API to plug into quickly, and almost every application uses at least one. Everyone is doing it! But only some people are doing it right. Creating a rich API that can be easily scaled requires planning. Unfortunately, most APIs developed these days, once deployed, can't be changed. Doing so usually breaks the client's code that relies on the API. So while it's good to remain consistent, we should give our APIs room for extension.
We believe API design should follow an open/closed principle: "software entities should be open for extension but closed for modification." Applying this principle will help your API evolve as the industry changes. Here are some of the best practices and pitfalls we've discovered to help you build a great API yourself.
Use nouns instead of verbs (RESTful)
Verb resources (bad practice)
Method | URI |
GET | /getAllPhotos |
POST | /addPhoto |
PUT | /updatePhoto |
DELETE | /deletePhoto |
PUT | /updateAllPhotos |
DELETE | /deleteAllPhotos |
GET | /getPhoto |
Developers may be tempted to be as descriptive as possible when structuring API resources. Take, for instance, the table above. Depending on your application's size, using verbs will result in a massive list of URLs. It's hard to keep track of such a list as a developer, but it's even harder for your API consumers as they will need to dig into the documentation for every task. An API should be designed so that users can guess or experiment successfully with the URLs.
Noun resources
Resource | GET | POST | PUT | DELETE |
/photos | Return list of all photos | Add a new photo | Bulk update all photos | Delete all photos |
/photos/3 | Return a specific photo | error | Update a specific photo | Delete a specific photo by identifier |
Above is an example of how we can structure our resources better and make the API easier to use. For example, we only need two resources, /photos and /photos/:id, in conjunction with four HTTP verbs (GET, POST, PUT, DELETE) to be able to perform the operations in our previous colossal list.
Use Transformers for data presentation
Another bad practice is querying the database and dumping everything as an API response. Instead, I recommend using transformers over dumping the database data to the world.
Transformers give you control over what data you output to your API consumers. With transformers, we are confident that sensitive information is not displayed by mistake. Not only is it a security measure, but transformers will also help prevent API consumers' code from breaking when your database schema changes.
While you can build your transformers easily, I recommend Fractal if you are in the PHP world. With transformers, you are afforded the benefit of serializing your data in a specific way and embedding related resources within each other.
Error handling
Use HTTP status codes
While there are more than a dozen status codes, we only need ten codes for REST. Your API consumers will know how to respond to the errors since the status codes are a standard. It would be best if you didn’t make your consumers rely on the error messages to determine how to proceed from an error. Below are the ten status codes you need to use:
200 | The request has succeeded |
201 | Resource successfully created |
204 | Request fulfilled but no content returned |
304 | Request not modified |
400 | Bad request. Reqeuest can not be understood by the server due to malformed syntax |
401 | Unauthorized. The request requires user authentication |
403 | Forbidden |
404 | Not found. Server can not find requested resource |
409 | Conflict. Request can not be completed due to conflict with the current state |
500 | Internal Server Error |
So don’t just return HTTP status code 200 for every request.
Error Codes and Messages
Apart from returning the correct HTTP status codes, it also helps to return custom error codes and verbose error messages for your API. These will go a long way if you have to offer support to your API consumers. Knowing the error code and message will make it easy to pinpoint the issue in your code.
Documentation
Are you happy to use an API without documentation? I’m hoping you answered “no.” So while documentation may be painful, you have to do it. Good resource documentation should at least include the following:
- Resource URL (api.example.com/photo/:id)
- Resource Information (Description, Response formats including - JSON and XML, Requires authentication?)
- Parameters (specify required/optional) and give examples
- Example request
- Example result
Including usage examples and tutorials will be a plus.
Including usage examples and tutorials will be a plus.
Authentication
Another critical aspect of API design is authenticating and protecting our applications. Below are some strategies you can use to authenticate clients using your API.
HTTP Basic authentication
This is a standard HTTP authentication mechanism whereby clients supply a username and password BASE64 encoded in the “Authorization” header.
Oauth2
Ouath2 comprise of the following two:
- user/client credentials to use in getting an access token
- Use the access token to access the API resources
However, since this involves transmitting access tokens and authentication credentials, Oauth2 is only secure if used with TLS/SSL to encrypt data during transmission. You also need to consider storing the client credentials on clients like mobile applications. There is a debate about this, as keeping the credentials for Oauth2 on a mobile or desktop app isn’t the most secure thing to do. If, for instance, our client credentials get compromised, then the Oauth2 provider has to revoke the entire application since we would have that information hard coded.
We have only scratched the surface here. There are a lot of techniques that we could talk about to make our APIs scalable and secure.