Angular Libraries and Microservices

We live in a Microservices world, and this world is there to stay. Back-end developers need to dive into Domain Driven Design, write stateless, resilient, highly available services, keep data synchronized through Change Data Capture, handle network failure, deal with authentication, authorization, JWT… and expose a beautiful Hypermedia API so the front-end developers can add a great user interface to it.

Good ! But what about the front-end ?

Let’s say we have several microservices, several teams, several APIs and, therefore, several user-interfaces. How can you create an integrated and consistent user interface so your users don’t actually see that there are as many user-interfaces as there are Microservices? In this article I’m implementing the Client-side UI composition design pattern using Angular Libraries.

A Microservice Architecture

Let’s say we have a CD BookStore application that allows customers to buy CDs and Books online, as well as administrators to check the inventory. We also have some complex ISBN number generator to deal with. If we model this application into Microservices, we might end-up splitting it into 3 separate microservices:

  • Store : deals with displaying information on CDs and Books, allows users to buy…
  • Inventory : allows administrators to check the availability of an item in the warehouse, buy new items if needed
  • Generator : generates ISBN numbers each time there is a new book created

We end up with two roles (user and admin) interacting with these 3 APIs through a single user interface:

 

Client-side UI composition

In a perfect Microservices’ world, these 3 Microservices are independent, developed by 3 different teams and therefore, have 3 different user interfaces, each released at its own pace. On one hand we have 3 different UIs, and on the other hand, we want our users to navigate into what they see as a single and integrated application. There are several ways of doing it, and the one way I’m describing here is called the Client-side UI composition design pattern:

Problem
How to implement a UI screen or page that displays data from multiple services?

Solution
Each team develops a client-side UI component, such an Angular component, that implements the region of the page/screen for their service. A UI team is responsible implementing the page skeletons that build pages/screens by composing multiple, service-specific UI components.

The idea is to aggregate, on the client side, our 3 user-interfaces into a single one and end-up with something that looks like this:

Aggregating several UIs into a single one works better if they use compatible technologies of course. In this example I am using Angular and only Angular to create the 3 user-interfaces and the page skeleton. Of course, Web Components would be a perfect fit for this use case, but it’s not the purpose of this article.

Angular Libraries

One novelty since Angular CLI 6 is the ability to easily create libraries. Coming back to our architecture, we could say that the page skeleton is the Angular application (the CDBookStore application), and then, each Microservice user-interface is a library (Store, Inventory, Generator).

In terms of Angular CLI commands this is what we have:

# Main app called CDBookStore
$ ng new cdbookstore --directory cdbookstore --routing true

# The 3 libraries for our 3 microservices UI
$ ng generate library store --prefix str
$ ng generate library inventory --prefix inv
$ ng generate library generator --prefix gen

Once you’ve executed these commands, you will get the following directory structure:

    • src/app/ is the good old Angular structure. In this directory we will have the page skeleton of the CDBookStore application. As you will see, this skeleton page is only a side bar to navigate from one Microservice UI to another one
    • projects/ is the directory where all the libraries end up
    • projects/generator: the UI for the Generator microservice
    • projects/inventory: the UI for the Inventory microservice
    • projects/store: the UI for the Store microservice

The Skeleton Page

The skeleton page is there to aggregate all the other components. Basically it’s only a sidebar menu (allowing us to navigate from one Microservice UI to another one) and a <router-outlet>. It is where you could have login/logout and other user preferences. It looks like this:

In terms of code, despite using Bootstrap, there is nothing special. What’s interesting is the way the routes are defined. The AppRoutingModule only defines the routes of the main application (here, the Home and the About menus).

const routes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'home', component: HomeComponent},
  {path: 'about', component: AboutComponent},
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

In the HTML side of the sidemenu bar, we can find the navigation directive and the router:

<ul class="list-unstyled components">  
  <li>
      <a [routerLink]="['/home']">
        <i class="fas fa-home"></i>
        Home
      </a>
      <a [routerLink]="['/str']">
        <i class="fas fa-store"></i>
        Store
      </a>
      <a [routerLink]="['/inv']">
        <i class="fas fa-chart-bar"></i>
        Inventory
      </a>
      <a [routerLink]="['/gen']">
        <i class="fas fa-cogs"></i>
        Generator
      </a>
  </li>
</ul>
<!-- Page Content -->
<div id="content">
  <router-outlet></router-outlet>
</div>

As you can see in the code above, the routerLink directive is used to navigate to the main app components as well as libraries components. The trick here is that /home is defined in the routing module, but not /str, /inv or /gen. These routes are defined in the libraries themselves.

Disclaimer: I am a terrible web designer/developper. If someone reading this post knows about JQuery and Angular and want to give me a hand, I would love to have the sidebar to be collapsible. I even created an issue for you ;o)

The Libraries

Now when we click on Store, Inventory or Generator, we want the router to navigate to the library’s components

Notice the parent/child relationship between routers. In the image above, the red router-outlet is the parent and belongs to the main app. The green router-outlet is the child and belongs to the library. Notice that in the store-routing.module.ts we use str has the main path, and all the other paths are childs (using the children keyword):

const routes: Routes = [
  {
    path: 'str', component: StoreComponent, children: [
      {path: '', component: HomeComponent},
      {path: 'home', component: HomeComponent},
      {path: 'book-list', component: BookListComponent},
      {path: 'book-detail', component: BookDetailComponent},
    ]
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class StoreRoutingModule {
}

The beauty of having a parent/child router relationship, is that you can benefit from “feature” navigation. This means that if you navigate to /home or /about you stay in the main application, but if you navigate to /str, /str/home, /str/book-list or /str/book-detail, you navigate to the Store library. You can even do lazy loading on a per feature based (only load the Store library if needed).

The Store library has a navigation bar at the top, therefore, it needs the routerLink directive. Notice that we only need to use the child path [routerLink]="['book-list']" without having to specify /str (no need to [routerLink]="['/str/book-list']"):

<nav>
  <div class="collapse navbar-collapse">
    <ul class="navbar-nav mr-auto">  
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle">Items</a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
         <a class="dropdown-item" [routerLink]="['book-list']">Books</a>
         <a class="dropdown-item" [routerLink]="['cd-list']">CDs</a>
         <a class="dropdown-item" [routerLink]="['dvd-list']">DVDs</a>
        </div>
      </li>
    </ul>
  </div>
</nav>
<!-- Page Content -->
<div id="content">
  <router-outlet></router-outlet>
</div>

Pros and Cons

The Client-side UI composition design pattern has some pros and cons. If you already have existing user-interfaces per microservices, and if each one is using totally different technologies (Angular vs React vs Vue.JS vs …) or different framework versions (Bootstrap 2 vs Bootstrap 4), then aggregating them might be tricky and you might have to rewrite bits and pieces to have them compatible.

But this can actually be benefit. If you don’t have extended teams with hundreds of developers, you might end-up being the one moving from one team to another one and will be happy to find (more or less) the same technologies. This is defined in the Chassis pattern. And for your end users the application will have the same look and feel (on mobile phones, laptops, desk tops, tablets), which gives a sense of integration.

With the way Angular Libraries are structured, having a mono repo is much easier. Of course each library can have their own life cycle and be independent, but at the end of the day it makes it easier to have them on the same repo. I don’t know if you love MonoRepos or not, but some do ;o)

Conclusion

We’ve been architecturing and developing Microservices for several decades now (yes, it used to be called distributed systems, or distributed services), so we roughly know how to make them work on the back-end. Now, the challenge is to be able to have a user interface which communicates with several Microservices, developed by different teams, and at the same time feels consistent and integrated for the end-user. You might not always have this need (see how Amazon has totally different UIs for its services), but if you do, then the Client-side UI composition design pattern is a good alternative.

If you want to give it a try, download the code, install and run it (there is only the front-end, no back-end APIs). And don’t forget to give me some feedback. I would be interested to know what you do to aggregate several user-interfaces into “a single one”.

References

Categories: angular

Tagged as: ,

7 Comments »

  1. Love the article. The Client-side UI composition pattern is what we (the Angular community) are promoting. Also, a great illustration of the Angular CLI.

    However, in the problem/solution orange block, you may wanna replace “such an AngularJS directive,” with “such an Angular Component”.

    Good read.

  2. Its a great pattern for microservices as long as the UX doesn’t involve heavy interactions within the microservices. If a page requires composition of multiple microservice UI components then it might be tricky. But in general yes its a great start for composing microservices. We considered the pattern when designing JHipster microservices originally but then decided to stick to having a monolith gateway for UI due to the usecase where a UI would require components and services from multiple microservice apps. I guess a perfect blend would be to use the composition pattern along with an event driven communication mechanism for the components to talk to each other. I also like the library approach.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s