Most articles on REST seem to focus only on APIs. This view misses several key benefits of a RESTful system. The true potential of REST is to build systems as scalable, distributed, resilient, and composable as the Web. Yes, APIs play a role in this but by themselves are not enough.
In Part 1 of this article I described the 6 architectural constraints, 4 interface constraints, and 3 architectural components defined in the REST architectural style. I also detailed why the API centric view of REST merely scratches the surface.
In this final part, I will show how to apply the full REST architectural style, discuss how the benefits are achieved, and provide a way to incrementally migrate to an RESTful architecture.
Applying the basic constraints
Lets try and build a conceptual system from the REST constraints and elements. Our first attempt uses the following constraints:
Client – Server: separation of client and server roles
Stateless: externalize all data & state (including request state) from the server. We can choose some combination of NoSQL, SQL, or distributed cache data management solutions.
Cache: add a cache component to the client, as well as the server
Uniform Interface: provide a RESTful API at the server
Layered System: the application and data tier are separated into layers
Since we made the application server stateless, we can now add a gateway component for common request management, and scale server instances up & down behind it. The gateway could be implemented using a load balancer or a reverse proxy, and itself can scale up or down as needed. Based on the choice of data management solution, we can also replace the single server with a cluster of data management servers.
We now have a classic tiered architecture and each tier is elastic. This may be good enough for some applications. In fact most current applications use this, or a close variant of this, tiered architecture.
However, this architecture will become quickly difficult to scale and manage in a cloud. Here are a few reasons why:
The application server is monolithic; scaling requires deploying the entire application as a separate instance.
The failure domain is the entire application. A single bug, or issue, can impact the full application.
A single type of data tier is assumed for the entire application. In reality, different modules will need different types of data management services.
Incremental changes, that impact only a small set of functions, are not possible to test and manage
To solve these problems we need to further apply the REST constraints on the application tier itself.
The next step would be to further decompose the application server, into multiple RESTful services. Lets say we had two top-level modules in our application, we can make each of them a separate service. A service is now the fundamental unit of deployment and management. Each service is stateless and has its own uniform interface. Each service has its own data cache and storage tier, and these can use different types of data management technologies based on the requirements. A service can also be scaled up or down independently of other services.
The tradeoff with this architecture is that now additional services will be needed to manage the inter-service communication. We can add a service registry to allow services to lookup services. The gateway also needs more intelligence for routing requests and finding services.
Businesses adopting cloud computing have also adopted a RESTful distributed cloud services architecture. Here are a few examples:
- Netflix transitioned from monolithic tiers to a cloud services approach. They have open-sourced their service registry (Eureka), gateway (Zuul) and several other components. Their engineering blog and the Netflix OSS GitHub repository are great resources.
- LinkedIn made the transition from monolithic application to distributed services. This InfoQ presentation from Jay Krepps is a great overview.
- Twitter switched from what they called a “monorails” application to distributed JVM based services. Jeremy Cloud discusses this in an InfoQ presentation, “Decomposing Twitter”.
- Amazon has not directly presented this, but there are reports of their architecture based on internal APIs and services.
- Yammer also uses a distributed services based approach, and has open sources a tool called DropWizard to aid in building RESTful Java services.
Applying to Existing Systems
If you are like most developers, it may seem like a stretch to even consider making bold changes to your system to move towards a RESTful architecture. However, the fine-grained services approach has another key advantage. You can leverage the emphasis on modularity to incrementally transform a monolithic application to a cloud services architecture.
You can select an existing module, or when its time to build a new module, built it as a library which can be run as part of your monolithic application or as a separate service.
If your goal is to build an elastic & composable system – like the internet, you need to learn more than the ‘uniform interface’ constraint in REST. In this article we applied all five required REST constraints, and used different architectural elements to build an elastic architecture where an application is composed of multiple RESTful services. This architecture yields several benefits, and most importantly enables continuous delivery of software. Now small, autonomous DevOps teams can build and manage individual services and get direct feedback on usage! Enterprises can incrementally adopt this architecture by migrating modules in a monolithic application.