Developer Story: Designing a Proper RESTful Server API Structure
As I discussed in a previous developer story entry, I believe that the server is the focal point for any software system where a client needs to communicate with a database. The database structure and the needs of the client are typically not compatible, if ever, so there is always a need for a server to translate data requests from the client into actual database queries for the database, and then translate the data response back into something sensible for the client to consume. The process of building this translation layer can be challenging because it requires organizing an often disparate collection of things into a logical structure that communicates not only subjects, but also verbs if you can picture client interactions with the database as being like conversations.
Since I have worked at many different companies during my career, I have witnessed a great many different “strategies” for how to handle this organization problem. I have seen some teams that did not really have any discernible plan as to how to accomplish this task and could never really bring all of their server API code under one coherent and consistent structure. On the other hand, I have seen other teams that did a great job with their server API organization and took great strides to ensure that as development continued the API structure did not fall prey to the organic dispersion that often plagues software systems and become buried under a mountain of technical debt. Of all the different strategies that I have seen deployed to solve this organization problem, the best one that I have seen and that makes the most logical sense to my overly logical brain is resource oriented design.
Developed by Google for many of their own myriad APIs, the stated goal of creating this design and releasing a guide for the public to follow is “to help developers design simple, consistent and easy-to-use networked APIs.” Since encountering this API design guide and seeing it work well professionally, I have not found another API design specification that so completely and elegantly communicates a solution for the organization problem that I discuss above. Most of the APIs that I build both professionally and personally are RESTful, so this design guide has been a godsend for all of the API architecting and building that I have to do. I have striven to adhere to the rules set forth in this guide as closely as possible in all of the APIs that I have developed since discovering it with the hopes that all of the those APIs are and remain easy to understand and easy to use.
For me, the aspect of resource oriented design that makes so much sense and distinguishes this approach to API design from others is that it considers the data being accessed and manipulated first before considering the actions being executed on that data. Per the guide, the nouns or data of the API are modeled as collections of individually-addressable resources. In other words, the collections represent the individual tables or collections in your database, while the resources represent the individual rows or documents contained within those tables or collections. Also per the guide, resources are referenced with their resource names and manipulated via a small set of methods, which are also known as verbs or operations. In the case of RESTful APIs, these methods or verbs would be the standard REST methods Create, Get, List, Update, and Delete.
So how about a practical example of how this would look? A perfect one comes from a project that I worked on at one of my previous companies, which involved developing a cloud-based IDE with file versioning. A subset of the API routes that I created for this project were the following:
To use the appropriate resource oriented design terminology, the projects, folders, and files referenced in these routes are the collections, while the
<file_id> referenced in these routes represent the individual resources. In order to specify a specific folder, you also have to specify its containing project, and in order to specify a specific file, you have to specify both its containing folder and its containing project. This API structure very clearly communicates the relationship of different types of resources to each other, while also providing many different routes on which to apply the standard REST methods. For example, in order to allow users of the system to create new folders in a project you can define the following route method:
And if you want to allow users of the system to update or delete a specific folder you can define the following route methods, respectively:
Now, the important thing to remember, which is also discussed in the guide, is that just because a route method uses a specific verb or a resource does not mean that you literally have to execute the action of that verb on the resource. Where necessary, resource oriented design provides room for creating “custom” methods, which are not actually custom and completely new HTTP methods but instead a repurposing or redefining of what they mean for a given collection or resource. So, for example, in the last route method that was defined, the DELETE action may not actually have to correspond to the physical deletion of a row or document from a table or collection in your database. It could simply correspond to a soft delete of that row or document, where the row or document is maintained in the database with a column or field value being set to indicate that the row or document has been “deleted”. This flexible use of HTTP methods both literally and figuratively is the other defining aspect of resource oriented design that sets it apart from any of the other ways in which I have seen APIs developed over the years.
While looking back on the various API implementations at my previous companies who did not follow resource oriented design, they were usually designed with the actions that could be performed through the API considered first and the data to be accessed or manipulated through those actions considered second. I truly believe that those APIs whose design broke down after continued development suffered their fates because of this illogical order of design. Typically, in most databases there are significantly more individual types of actions that you would need to perform than there are logical groups of data to perform those actions on. It is much better to divide and conquer initially where there are fewer divisions, before further dividing and conquering on those divisions, which is why first dividing by data groups before dividing by actions is, in most cases, the proper way to design an API. All RESTful API development that I do on my personal project will follow the resource oriented design guide. Please stay tuned for the results of that development and much more as I make further progress on my personal project.