Healthe-master

This project is open source software system implemented with microservice architecture.

View on GitHub

DESIGNING A ROBUST AND SCALABLE HEALTH ANALYSIS/MANAGEMENT API WITH MICRO-SERVICE ARCHITECTURE

Being a web application, it is highly dynamic and it needs to be scalable with minimum efforts put to integrate it in the existing environment. Hence in this scenario building a large scale web based distributed system, micro-services architecture emerged in recent years. Through this project I wish share my early experience with micro-service architecture to design a scalable Health Analysis/Management platform with recent industry recently developed and most used services for load balancing, monitoring, API proxy,security, etc. and compare the benefits and challenges of distributed systems with traditional monolith architectures.


Index

  1. Run Code on PC
  2. Layered Architecture
  3. Infrastructure
  4. Database Configuration
  5. Context Diagram
  6. Actual Database Configuration Theory
  7. Deliverables
  8. Gateways
  9. Microservice Tenents
  10. Run Code on PC


Layered Architecture

  1. As depicted in above figure the architecture is divided into 3 sections each having its own set of responsibilities :

    • API Service layer : responsible for performing authorization and load balancing for next level of processes.
    • Composite Layer : responsible for performing abstraction and acts as a single point of contact for the external requests. It also manages circuit breaking process to increase fault tolerance
    • Core Layer: consists of core services supported by the system which includes managing cache, database and business logic.

Infrastructure

Database Configuration

The Schema configuration is simulated as per the following diagram below :

Click here to enlarge : ER Diagram

Note : Word Simulated is used since basic SQL constraints are not possible on database per service architecture.

Context Diagram

Below is Context Diagram for better understanding of the overall working of the system,

Brief about actual database configuration

Deliverables

Below listed are all the deliverabeles of the project:

  1. Core Services
    • Forum API : This service is reponsible for managing community discussion forum
    • Appointment Booking API : This service is reponsible for managing appointment management with patient and doctor as end users.
    • Store Locator API : This service is reponsible locating nearby pharma stores.
    • Diagnosis API : This service makes call to django servers which consists of below services:
      1. Heart Attack Predictor API : This service is reponsible for taking in readings as input and returning diagnosis with probability.
      2. Stroke Risk Analysos API : This service is reponsible for taking in readings as input and returning diagnosis with probability.
      3. Diabetes Pridictor API : This service is reponsible for taking in readings as input and returning diagnosis with probability.
    • Medication Management API : This service is responsible for managing prescription of patient.
  2. Support Services
    • Authorization and Authentication API : This API is responsible for performing Token based SSO authentication and authorization.
    • Mailing API : This API is responsible for dispastching mails to user whenever reuqired.
    • Proxy Server : This server is reponsible for proxying requests to application.
    • Service Discovery Server : This servers acts as Service Registry and helps in the process of service discovery.
  3. Gateway Services
    • Catalog Service : This API acts as a gateway to the entire system and only authenticated requests can pass through this gateway.

Forum API

Purpose

Endpoint Method Description
/subreddit-create POST Creates a new thread


Json Format Example

{
    "name":"Thread Name",
    "description":"This is First Thread",
    "numberOfPosts":0
}


Endpoint Method Description
/post-create POST Creates a post under a thread


Json Format Example

{
    "subredditName":"Thread Name",
    "postName":"This is under First Subreddit",
    "url":"www.firstSubreddit.com",
    "description":"This is description post first seventh Subreddit"
}


Endpoint Method Description
/create-comment POST Creates a comment under a post


Json Format Example

{
    "postId":1,
    "text":"This is a third comment for postId 1 under 1 subreddit"
}


Endpoint Method Description
/userposts GET Returns all the posts created by a user
/post-thread/{thread-id} GET Gets all posts under the thread with given id
/thread-list GET Gets all threads
/thread/{thread-id} GET Gets threads information with given id


Endpoint Method Description
/vote POST Creates a UPVOTE or DOWNVOTE for a post


Json Format Example

{
    "voteType":"UPVOTE",
    "postId":"1"
}


Endpoint Method Description
/post-comment/{post-id} GET Gets all comments for a post with a given id
/post-comments GET Gets all comments for a post
/comment-delete/{commnet-id} DELETE Deletes comment with given id
/post-delete/{commnet-id} DELETE Deletes post with given id


Appointment Management API

Purpose

Endpoints


Endpoint Method Description
/patient-register POST Creates new patient Profile


Json Format Example

{
    "pat_name":"Arnob_123",
    "pat_phone":"87171691191",
    "pat_dob":"03-09-1999",
    "pat_gender":"M",
    "enrollDate":"09-09-2020",
    "insured":"Y"
}


Endpoint Method Description
/patient-update PUT Updates patient Profile


Json Format Example

{
    "pat_name":"Arnob_123",
    "pat_phone":"87171691191",
    "pat_dob":"03-09-1999",
    "pat_gender":"M",
    "enrollDate":"09-09-2020",
    "insured":"Y"
}


Endpoint Method Description
/patient-app-booking POST Updates patient Profile


Json Format Example

{
    "docId":"testuser5",
    "appTypeId":1,
    "startDate":"2021-03-13",
    "startTime":"6:30:59",
    "endTime": "7:00:00"
}


Endpoint Method Description
/doctor-register POST Creates a new Doctor Profile


Json Format Example

{
    "doc_name":"Arnob chowdhury",
    "doc_phone":"87171691191",
    "doc_address":"Valentus, Gaur City mall CR",
    "dateOfStarting":"1978-09-09",
    "doc_gender":"M",
    "doc_dob":"1978-09-09",
    "doc_settlePoint":"22.2323,45.4433",
    "doc_description": "Did MBBS and MD from Boston, Heart specialist",
    "docSpecId": 1,
    "clinicId": 1
}


Endpoint Method Description
/doctor-update POST Updates Doctor Profile


Json Format Example

{
    "doc_name":"Ikala Chuhioq",
    "doc_phone":"8717123455",
    "doc_address":"Valentus, Gaur City mall CR",
    "dateOfStarting":"1978-09-09",
    "doc_gender":"M",
    "doc_dob":"1978-09-09",
    "doc_settlePoint":"22.2323,45.4433",
    "doc_description": "Did MBBS and MD from Boston, Heart specialist",
    "docSpecId": 1,
    "clinicId": 1
}


Endpoint Method Description
/doctor-update POST Updates Doctor Profile


Json Format Example

{
    "doc_name":"Ikala Chuhioq",
    "doc_phone":"12345667890",
    "doc_address":"Valentus, Gaur City mall CR",
    "dateOfStarting":"1978-09-09",
    "doc_gender":"M",
    "doc_dob":"1978-09-09",
    "doc_settlePoint":"22.2323,45.4433",
    "doc_description": "Did MBBS and MD from Boston, Heart specialist",
    "docSpecId": 1,
    "clinicId": 1
}


Endpoint Method Description
/patient-profile GET Returns Patient Profile
/patient-get-booking GET Returns Patient Booking information
/doctor-delete DELETE Deletes doctor’s profile
/doctor-schedule GET Returns Doctor schedule to avoid overlapping


Store Locator API

Purpose

Endpoints

Endpoint Method Description
/booking/allmarkers GET Returns coordinates of all the stores.
/near/{latitude:.+},{longitude:.+} GET Returns coordinates of all the stores near given latitude and longitude


Endpoint Method Description
/create POST Registers a pharamacy stores with given coordinates coordinates.


Json Format Example

{
    "storeName":"books testing",
    "streetName":"NEw Street 1 ...",
    "location": {
      "type": "Point",
      "coordinates": [12.1212, -45.2331]
    }
}




Diagnosis API

Purpose

Endpoints

Endpoint Method Description
/diabetes-diagnosis POST Sends reading for ML model to process and returns the outcome


Json Format Example

{
    "glucose":140.0,
    "insulin":0.0,
    "bmi":23.3,
    "age":50
}


Endpoint Method Description
/stroke-diagnosis POST Sends reading for ML model to process and returns the outcome


Json Format Example

{
    "gender":1,
    "ever_married":1,
    "work_type":2,
    "residence_type":1,
    "smoking_status":1,
    "age":67, 
    "hypertension":0,
    "heart_disease":1, 
    "avg_glucose_level":229, 
    "bmi":37
}


Endpoint Method Description
/heart-diagnosis POST Sends reading for ML model to process and returns the outcome


Json Format Example

{
    "age":63,
    "sex":1,
    "cp":3,  
    "trestbps":145,  
    "chol":233, 
    "fbs":1,  
    "restecg":0,  
    "thalach":150,  
    "exang": 0, 
    "oldpeak":2, 
    "slope": 0,
    "ca":0,
    "thal":1
}


Endpoint Method Description
/get-heart-record GET Returns stored Diagonis Report
/get-diabetes-record GET Returns stored Diagonis Report
/get-stroke-record GET Returns stored Diagonis Report


Medication API

Purpose

Endpoints

Endpoint Method Description
/create-medication POST Creates Precription and stores with User Location


Json Format Example

{
    "patId":"testuser4",
    "coordinates":[12.1212,-45.2321],
    "medication":[{
            "medName":"paracitalom",
            "time":"morning"
        },
        {
            "medName":"cyrus",
            "time":"night" 
        },
        {
            "medName":"cyrus_19191",
            "time":"night" 
        }
    ]
}


Endpoint Method Description
/get-medication GET Returns Medication record of patient
/get-stores GET Returns nearby stores to user location
/handover-medicines/{pat-id} DELETE Deletes patient record from to be picked up medicines.


Support APIs

Authentication and Authorization API

Purpose

Explanation

Endpoints

Endpoint Method Description
/api/auth/signup POST Registers a new User and sends email for verification purpose


Json Format Example

{
    "username":"testuserd7",
    "email":"testuser7@gmail.com",
    "password":"test789",
    "role":"DOCTOR"
}


Endpoint Method Description
/api/auth/accVerfication/{token} GET Activates User account by comparing one time token sent on mail


Endpoint Method Description
/api/auth/login POST Returns Encryted Access Token and Expiration.


Json Format Example

{
    "username":"testuser4",
    "password":"test456"
}


Endpoint Method Description
/api/auth/logout POST Deletes users security context.


Json Format Example

{
    "username":"testuser4",
    "password":"test456"
}


Mailing API

Purpose

Endpoints

Endpoint Method Description
/sendmail POST Sends mail with required body

GATEWAYS

Service EndPoint
auth-service /auth/**
forum-service /forum/**
app-service /appointment/**
catalog-service /catalog/**
medication-service /medication/**
diagnosis-service /diagnosis/**

Microservice Tenents

Circuit Breaker

Purpose

Explanation

Implementation

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;


@SpringBootApplication
@EnableCircuitBreaker
@EnableHystrixDashboard
public class CatalogServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(CatalogServiceApplication.class, args);
	}

}


application.porperties Configuration :

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=2000
management.endpoints.web.exposure.include=hystrix.stream
hystrix.dashboard.proxyStreamAllowList=*

Service Registry and Discovery

Purpose

Problems

Implementation Example

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class ServicedisApplication {

	public static void main(String[] args) {
		SpringApplication.run(ServicedisApplication.class, args);
	}

}

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.scheduling.annotation.EnableAsync;


@SpringBootApplication
@EnableAsync
@EnableEurekaClient
public class RedditApplication {

	public static void main(String[] args) {
		SpringApplication.run(RedditApplication.class, args);
	}

}

Load Balancing

Implementation Example


@GetMapping("/get-stores") //hystrix
@HystrixCommand(fallbackMethod = "getNearByFB")
public Object getNearBy(@RequestHeader(value = "Authorization") String token){
	HttpHeaders headers = new HttpHeaders();
	headers.setContentType(MediaType.APPLICATION_JSON);
	headers.set("Authorization", token);
	HttpEntity<String> entity = new HttpEntity<String>(headers);
	
	String uri = loadBalancer.choose("medication-service").getServiceId();
	
	String url = "http://"+uri.toString() + "/medication/nearByStore";
	ResponseEntity<Object> responseEntity = restTemplate.exchange(url,HttpMethod.GET,entity, Object.class);
	Object res  = responseEntity.getBody();
	return res;
 }

Used Netflix OSS:

Run on your PC without Docker

NOTE : You need to configure your own jks files for communication level security in application.properties file whereever needed.

What Will You Build

You will build a web application that is Oauth2 enabled.

What you will need

To clone and the project do the following

Configuring Database


spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.datasource.url =jdbc:mysql://localhost:3306/<your database>
spring.datasource.username = <username>
spring.datasource.password = <password>
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true

#hibernate
#spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true



spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.datasource.url =jdbc:mysql://localhost:3306/<Your Database>
spring.datasource.username = root
spring.datasource.password = <password>
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true


spring.user.jpa.database-platform=org.hibernate.dialect
.MySQL8Dialect
spring.user.datasource.jdbcUrl= jdbc:mysql://localhost:3306/<your database>
spring.user.datasource.username = <username>
spring.user.datasource.password = <password>
spring.user.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.app.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.app.datasource.jdbcUrl=jdbc:mysql://localhost:3306/<your database>
spring.app.datasource.username = <username>
spring.app.datasource.password = <password>
spring.app.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database=default
spring.jpa.show-sql=true


spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=<your database>
spring.data.mongodb.repositories.enabled=true
# mongod --dbpath "<path to your db>"

spring.user.jpa.database-platform=org.hibernate
.dialect.MySQL8Dialect
spring.user.datasource.jdbcUrl =jdbc:mysql://localhost:3306/<your database>
spring.user.datasource.username = <username>
spring.user.datasource.password = <password>
spring.user.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database=default
spring.jpa.show-sql=true


spring.user.jpa.database-platform=org.hibernate.dialect
.MySQL8Dialectspring.user.datasource.jdbcUrl=jdbc:mysql://localhost:3306/<your database>
spring.user.datasource.username = <username>
spring.user.datasource.password = <password>
spring.user.datasource.driver-class-name = com.mysql.cj.jdbc.Driver

spring.app.jpa.database-platform=org.hibernate.dialect
.MySQL8Dialectspring.app.datasource.jdbcUrl=jdbc:mysql://localhost:3306/<your database>
spring.app.datasource.username = <username>
spring.app.datasource.password = <password>
spring.app.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database=default
spring.jpa.show-sql=true


spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=<your database>
spring.data.mongodb.repositories.enabled=true