Wednesday, August 19, 2020

Microservice


Identity Server (wso2 IS)

This is an external identity server (out of scope) that provides authentication and authorization.

Service Provider

Spring security module (Gateway) should be configured as service provider with SAML2.0 support. But there should be a possibility to integrate third party SPs.

Config Server (Spring Cloud Config)

Config server provides a way to externalize configurations in a microservice environment. This is important when service instances are added dynamically according to the load. This server should be configured with git to store configuration files. Config server communicates with services via cloud bus. (eg: Configuration changes).

Tracing Server (Zipking Distributed Tracing)

This is just a log tracing server that collects HTTP request tracing from microservices and store them. Spring cloud sleuth should be configured with each service to get information from this server.

Integration Server (Spring Cloud Data Flow)

While the APIs available for integration with third party application, Spring cloud data flow is used for real time data pipeline and batch processes (ETL).  This is based on event stream technology. Spring cloud stream and Spring cloud data flow shell should be there in a microservice to work.

Cache Server (Hazelcast).

For the moment, we are planning to keep one cache server for all services. Same cache server will be used to store user sessions (If there is a requirement) and API request caching.

Event store (Axon)

Event store is used to persist events that are used in event sourcing. (For audit)

Service Registry (Consul)

In this architecture microservices are deployed in containers that has one IP for each container. Therefore, API gateway should have a list of services with IP addresses to send user request to the correct service.

Load Balancer (Spring Cloud Load Balancer)

Instead of traditional server-side load balancing, spring cloud load balancer provides client-side load balancing that has many advantages. To configure this, there should be a working service registry.

API Gateway (Spring Cloud Gateway)

This is the façade for API. Since there are lot of microservices (Even multiple instances of a single microservice), having a single-entry point is easy for API users. API gateway provides simple way to route to APIs and provides cross-cutting concerns to them such as security, monitoring/metrics, and resiliency.

Cloud Bus (Spring Cloud Bus)

This event-based communication channel (Event bus) has three major tasks in this architecture. RabbitMQ should be configured as a message queue.

  • 1)     Broadcast config changes among services.
  • 2)     Service to service async communication.
  • 3)    Communicate with Integration server.

UI Service

Micro front-end based UI (Please UI architecture) that deployed on a single server. There should be a possibility to configure CDN for static content whenever there is a requirement.

Authorization

If there is no way to use external IDP for authorization, then only this service should be built to store permissions.

Notification

All the notifications generated by services should be sent to notification service via cloud bus as an event (Async) and then should be stored in DB. Message workers should be written in this service to send SMS and Email.

X (Common modules)

Y (New modules)




Architecture of microservices

Except cache and UI, other services might (Services has autonomy to follow any architecture) follow this architecture. Every service consists of three parts. Business logic, business rules and settings (Settings related to this service). Service to service communication can be done using openFeign (or RestTemplate). For the async communication cloud bus should be used.


Rest Controller

This is the API entry point. All the user’s requests come here according to request mapping parameter. These methods consume and produce JSON objects. Proper HTTP method (GET, POST, and DELETE) should be used with controller methods. Every method should have userID and ClientID (this is for public SaaS) since the API is stateless.

Service

This layer is used to code business logic with the help of a rule engine.

Repository

This layer holds logic required to access data. There should be repository only for aggregate root (Entity that does not have parent entity)

Model

This is the lower-level layer that has entity in the problem domain. These classes should not have any methods other than getters, setters, equals, hash and toString. Use Lombok for getters, setters, no-args constructor and for equals and hash methods If there is a possibility.

Rule Engine (Drools)

All the business rules should be written in drool files. Main advantage of rule engine is maintainability. Without changing the source code anytime business logic can be changed according to the client’s requirement.

Transaction Management

Transaction management follows Events – driven architecture using Spring cloud stream. In this approach, any state change is an event. For instance, schedule create, schedule publish, bid for open shift, bidding failure and Schedule create failure. If an event is failed, all the tasks in the event chain should be rolled back using subscribed failure events.

Audit

Audit is based on event sourcing. Events that change the state of the system should be stored as immutable objects in a separate server to trace history. Example events: ScheduleCreated, RequestApproved, SchedulePublished.

 

Following spring modules should be configured with every service.

  • 1)     Spring cloud openFeign(REST) – synchronous communicate with services (RestTemplate(Sync)/WebClient(reactive))
  • 2)     spring actuator – Provides Health check, metrics, and audit
  • 3)     Spring Rest Doc – API documentation
  • 4)     Circuit Breaker (Spring cloud circuit breaker - resilience4j) - prevents failure cascading and improve resilience.
  • 5)     Liquibase – DB migration
  • 6)     Drools rule engine
  • 7)     Spring cloud sleuth – log tracing.
  • 8)     Spring cloud stream + Spring cloud data flow shell (For integration with the help of spring cloud data flow server)


Additional points for microservice

  • ·       All the temporal data should be stored in GMT- 0 time zone. When a HTTP request comes from different time zone, the result should be converted to the same time zone if the time zone is not sent manually.
  • ·       Auditing is implemented based on event sourcing technique.
  • ·       Session management – Spring session should be used in the server side and stored in the cache server.



API naming convention

  • 1)     Only noun can be used for resource naming. Unless it is singleton, it is better to use plural noun.
  • 2)     Use query parameters for sorting and filtering.
  • 3)     Only lowercase letters are allowed. Hyphen (-) can be used to separate words.
  • 4)     No jargons, No abridge(shorten), No file extensions, No trailing forward slash.
  • 5)     Use proper HTTP method (POST, GET, DELETE, PUT) names to indicate which CRUD function is performed.

Frontend Architecture

UI architecture is based on micro front-end, but all the modules of UI are deployed on single server and rendered on same server by using node. Whenever we have high demand, those UI modules will be deployed separately. This container app should be developed using single SPA. Parcel can be used to communicate between UI apps. There should be one UI app for one domain.


Frontend App Architecture

React based UI apps should follow this architecture. Every app should provide menu, settings, and pages to single SPA container app.


View

View is generated using react re-usable components.

Action

User actions (button click)

Dispatcher (Redux-saga)

Calling APIs and updating status are the main responsibilities of this middleware by dispatching user actions.

Redux-saga-request-axios should be used to send ajax requests.

API

Backend microservices

Store

Store holds whole state(immutable) of the application, and it consist of two parts.

1)    Reducer – reducer functions are used to change the state

2)     State – information that is used to update the UI

LocalizationLocalization is implemented on client side. Find a react plugin for i18n



Security Architecture


A

1)     HTML Meta data security

                              i.          Referrer

                            ii.           Content security policy to prevent XSS (cross site scripting) with default-src, style-src, script-src and frame-ancestors ‘self’

 

B

1)     URI Path, Query Param, Header, and JSON Payload should be protected by regular expression as required.

2)     IP access control.

3)     Spike arrest and quota policy.

4)     Handle invalid resources.

5)     HTTP verb validation.

6)     DoS and DDoS protection.

7)     Enumeration attack (Config spring security)

8)     Session fixation (Config spring security)

9)     Click jacking (Config spring security)

10)  CSRF (Config spring security)

11)  User data sanitization (using a filter or Jsoup xss)

12)  Secure, HTTPONLY and SameSite Cookies

13)  Security header integration

a.     HTTP strict transport security (Web server config/only support HTTPS)

b.     X-content-type (MIME sniffing)

c.      Cache control (max-age=<seconds>)

 

 

C

1)    API key and auth token verification

2)    SSO connect (RBAC user identity)

D

1)    Logging and tracing HTTP request

E

1)    Data validation

2)    Proper exception logging (Cannot throw any exception in the REST controller layer)


Monday, October 12, 2015

JQuery (Mobile) Date picker



JQuery (Mobile) Date picker

One day I wanted to find a date picker like iOS native date selector for a JQuery mobile project. Unfortunately I couldn't find any date picker for my requirement even though I searched all over the internet. So I decided to develop a plugin by myself.

Date picker


HTML input tag
 <input id='datepicker' type="text" />

Script :
  jQuery("#datepicker").dateSelector({
                        onChange: function(date) {
                            var currDate = formatDate(date);                          
                        }
                    });

Default options:
position: "C", // T-top C-center B-bottom I-inline
selectedDate: new Date(), // today
maxDate: null,
minDate: null,
dateFmt: "MM/dd/yyyy",
dmyOrder: "MDY", // Month Day Year
monthFormat: "NNN", // MM,MMM,NNN (02,February,Feb)
onChange: function(date) {} // Empty function

You can download the plugin from my google drive


References:
swipedown swipeup Events:  www.adomas.org
dateFormat: www.mattkruse.com

Sunday, October 11, 2015

JQuery Check box matrix plugin.

JQuery Check box matrix plugin.


Whenever you have a situation to check all the sub categories when you check on a main category, then you can use this plugin. This works with iCheck plugin. For example when you click on category 2 - s2 plugin will click Grade1 - s2 and Grade2-s2 automatically. You have to include a main category in a separate tbody tag.




HTML Table :

<table id="tableID" >
<thead>
<tr>
<th></th>
<th>s2</th>
<th>s3</th>
<th>shift test</th>
</tr>
</thead>

<tbody>
<tr>
<td>Category 2</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td>Grade 1</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>
<tr>
<td>Grade 1</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>

<tr>
<td>Grade 2</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>
</tbody>

<tbody>
<tr>
<td>Test cat 2</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>

<tr>
<td>Grade 5</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>

<tr>
<td>Grade 6</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>

<tr>
<td>Grade 7</td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
<td><input type="checkbox" /></td>
</tr>
</tbody>
</table>




Jquery plugin:

(function($) {
        $.fn.treeCheckTable = function() {           
        $(this).find("tbody").each(function(){
            var tbody = $(this);
            var headTr = $(this).find("tr:eq(0)");
            var lock = false;
            $(headTr).find("td:eq(0)").css("cursor","pointer");
            var bodyTrs = $(tbody).find("tr:gt(0)");
            var trCount = bodyTrs.length;
            $(this).find("tr:gt(0)").css('display','none');
            // show/hide children
            $(headTr).find("td:eq(0)").click(function(){
                $(bodyTrs).toggle();
            });

            // Header input checkbox click
            $($(headTr).find('input')).on("ifToggled",function(event){   
                 if(!lock){
                     lock = true;
                  var index = $(this).parents().parents().index();
                  var isChecked = $(this).is(":checked");             
                  $(bodyTrs).each(function(){
                    $(this).find("td:eq("+index+") input").iCheck(isChecked?"check":"uncheck");
                  });                 
                  lock = false;
                   }
           });       
             // body input checkbox click
           $($(bodyTrs).find('input')).on('ifToggled',function(event){  
               if(!lock){
                   lock = true;
                     var index = $(this).parents().parents().index();   
                     $(this).iCheck("update");
                  var inputCheckedCount = 0;                 
                  $(bodyTrs).find("td:eq("+index+") input").each(function(){                          
                      if($(this).is(":checked")){
                         inputCheckedCount++;
                      }                                           
                  });                 
                  $(headTr).find("td:eq("+index+") input").iCheck(trCount == inputCheckedCount ?"check" :"uncheck");                
                  lock = false;
               }
               });
            // Update tbody Headers (category row)                          
            $(headTr).find("td:gt(0)").each(function(i){                           
                      var td = $(this);                          
                      var count = 0;
                      $(bodyTrs).find("td:eq("+(i+1)+")").find("input").each(function(){
                      $(this).iCheck("update");
                      if($(this).is(":checked")){                                 
                        count++;
                      }                                           
                      });                               
                      if(trCount == count)
                          $(td).find("input").iCheck("check");                               
             });
        });
    };
}(jQuery));