Convergent UI: Distributed Composition with Microservices and Spring Cloud
Microservices Architectures are taking the development community by storm lately. As distributed systems continue to grow, so do the tools that surround them. Projects like Spring Cloud have provided common services that help support distributed systems using proven technologies from companies like Netflix. Spring Cloud provides services for distributed configuration management, service discovery, circuit breakers, proxy services, and much more. While these infrastructure services help developers to spin up cloud deployments quickly, we are still left with other gaps in the architecture that need to be solved.
When building a Microservices Architecture, we are told to separate concerns as much as possible, and to us, that also means separating the UIs from each other. At the same time, there is a desire to have a unified UI that doesn’t look/act like a frameset from the 90’s. Distributed Composition is a term that describes the need for a single UI to include pieces of UIs from many services and we feel this is a gap within the Microservices Architecture that needs to be filled.
In looking for a solution to this problem, we ran across a great article by Clifton Cunningham on Medium and his work on Compoxure. We decided to work on porting their architecture to our Spring Cloud based Microservices Architecture. The Compoxure Architecture used many similar constructs available within Spring Cloud, so it made sense to us to port the ideas proposed by Clifton to the Spring framework. To summarize Clifton’s approach, he described a Proxy that would handle composing a single UI from multiple backend services which they implemented as Compoxure using many Node.js features along the way. If you are interested in a more indepth description of the problem, and different options for solving this problem, please read Clifton’s article or as presented by Dejan Glozic.
At ACES, Inc., we strive to build robust architectures and have implemented many or our products using the Microservices Architecture patterns. We also want to give back to the community and share the technology that helps us with our services as well. So today, we would like to share the result of the work we have done in trying to solve the Distributed Composition problem within a Spring Cloud architecture and would like to introduce you to Convergent UI.
The Spring Cloud Architecture, which relies on many of the Netflix Open Source projects, provides a proxy called Zuul. The Zuul Edge Server provides a mechanism to inject Filters into the processing stream which is where we inject the
ConvergentUIFilter. The Spring Framework and Spring Cloud also provides Circuit Breakers and Caching mechanisms that help us implement many of the other robust features described in the Compoxure architecture.
ConvergentUIFilter scans HTML coming across the Proxy for content enriched with some special tags. These tags are processed in realtime and can reach out to other services running within your architecture that have been registered in a Discovery Service. Convergent UI will retrieve content from those other services and will replace the content within your composed HTML page, just like a Server Side Include.
As an example, say you have two services,
service1 may provide your main user interface for your customers, and
service2 may provide a specialized portion of your user interface that you would like to include within
service1‘s UI. Each of these services when running within your Spring Cloud architecture will have registered with the Discovery Service as ‘service1’ and ‘service2’ making them discoverable by those names to other services within your architecture and now by Convergent UI.
Within the main page for your
service1, you may have a
<div> that you would want to replace with
service2 content. In order to utilize Convergent UI, you would include a HTML snippet that may look like this:
<div data-loc="https://service2/test2" data-fail-quietly="false" data-fragment-name="test1" data-cache-name="service2:test2"> replace me! </div>
service2 could then provide HTML content at it’s
test2 endpoint that may look like this:
<!DOCTYPE html> <html> <head> <title>Test 2</title> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> </head> <body> <div>This is test page 2</div> <div data-fragment-name='test1'> This is content from Service 2! </div> </body> </html>
When someone requests your
service1 page, it will pass though the Convergent UI filter and the “replace me!” content would be replaced with the content provided by
service2 and the resultant
<div> would look like so when served to the client:
<div data-loc="https://service2/test2" data-fail-quietly="false" data-fragment-name="test1" data-cache-name="service2:test2"> <div data-fragment-name='test1'> This is content from Service 2! </div> </div>
If you are interested in learning more about how Convergent UI works and how you can use it in your project, we have released it on our GitHub page. If you like it, please Star it on GitHub, or leave us a note on Twitter/Facebook! We hope this helps others working with Microservices as much as it has helped us.