Can REST Expose Course Grained APIs?
Firstly, I must state that I am an avid fan of REST and always try to use it where possible. I researched REST for my bachelors dissertation at University, and whilst I found it made a lot of academic sense, I always struggled to see its commercial viability for exposing complex APIs.
My doubts have since been confirmed as we've started to adopt Patterns of Enterprise Application Architecture within our designs. More specifically, we have identified that REST cannot expose coarse-grained interfaces due to its inability to mix action types and limited support for referencing multiple resources in a single operation.
Why would we want to do this? Well, let's take a look at how an enterprise application is layered using P of EAA design concepts:
- Data Access Layer (typically an ORM). Provides a core querying interface (e.g. CRUD).
- Domain Layer. Provides a set of basic operations which conform to the system's constraints (e.g. a 'CreateAccount' method performing validation, or a 'GetByPassword' method performing hashing).
- Service Layer. Provides access to the system's use cases (e.g. 'Delete members who have not paid their latest bill and update product availability').
Here we can see 3 layers with varying levels of granularity, ranging from fine to coarse, respectively. The former 2 layers encapsulate most of the system's complexity, whereas the latter is essentially a collection of façades which route calls off to the domain logic. The importance of this layer is controversial, but it does provide several significant benefits to justify its appearance in most designs:
- Coarse-grained service layers provide a high level of abstraction which map directly onto use cases, thus making the codebase very descriptive.
- Service layers can also adsorb considerable changes in requirements, since they abstract away the workflow of each use case. Additive changes to use cases often require new domain layer methods to be implemented, since they cannot sensibly be applied by mutating existing domain layer methods. For example ‘Unsubscribe from Newsletter’ and ‘Delete Member’ are orthogonal operations, so their implementations shouldn't be combined. Instead, they should be implemented distinctly in the domain layer, and combined into a workflow as a service layer method to represent the use case for un-registering members. Systems without service layers require extensive inspection to identify and refactor code blocks which represent changing use cases.
- Finally (and more relevantly), they also provide a more efficient foundation for performing RPCs, since fewer methods have to be called to achieve a given task.
Now, it is apparent that a REST API could easily expose the data access layer. In fact, a REST API could quite easily expose the domain layer too, since the interface is still relatively fine-grained at this point.
However, the service layer is very different. Not only are we interacting with 3 resources in this example, but we're also using 2 different actions (delete and update), thus making the operation impossible to express in a single HTTP request. If we did decide to split the actions into 2 operations, then we would immediately be faced with transactional complexities.
Unfortunately I cannot see an easy way to remedy this. I therefore find myself coming to the same conclusion as many others have: SOA for complex enterprise APIs, REST for simple or adhoc APIs. Apologies for selling-out on you REST, at least you can't say I didn't try.