Kick-start your microservice project with JHipster

No Comments

I recently looked for a solution on how to prototype a customer project in a short time and came across JHipster. The target architecture used spring boot in the backend and an angular frontend. JHipster can scaffold this in its simplest variant as a monolithic project. But JHipster can do even more: it generates microservice architectures with all the associated state-of-the-art tooling that you need to deploy and run professional microservice projects.

I have always been a friend of avoiding boilerplate coding and have enjoyed using Xtext DSL in my projects to generate applications. In addition to the interactive interview mode, JHipster also provides a descriptive language for project creation called JDL. This blog post explains this quick, repeatable and easily understandable approach.

What is JHipster?

JHipster is an open source development platform to generate, develop, test and deploy web applications and microservice architectures.

For the frontend there are 3 different flavors: Angular, React and Vue. It includes Bootstrap and HTML5 Boilerplate, NPM, I18N support, Jest, Cucumber and Protractor, so there is nothing missing for a professional frontend developer.

In the backend, JHipster relies on Spring Boot but is not limited to it. It heavily exploits Spring additions like Security, MVC Rest, Data JPA and Websocket. The most common SQL and NoSQL databases are supported for the persistence layer. With Elasticsearch you get search capabilities on top of your database. Most interesting for me for high-availability microservice architectures: Kafka as messaging system. The biggest sticking point in a heavy loaded system is the buffering of messages in a queue in order not to lose any customer requests.

To set up microservices cleanly, routing and service discovery are carried out with Zuul and Eureka from Netflix, but Traefik and Consul could also be your choice. Runtime monitoring is done with the ELK stack.

Security is provided with 4 different mechanisms: JWT, session-based authentication, OAuth2 and OIDC, or JHipster project UAA which is dedicated to microservices using the OAuth2 authorization protocol. Using the OAuth2/OIDC option enables your application to work directly with Keycloak.

Finally, JHipster also supports the deployment for all major cloud providers: AWS, Cloud Foundry, GCP, Heroku, Kubernetes, OpenShift, Azure, Docker.

JHipster will generate a basic CRUD application running out-of-the-box according to your choices for all the mentioned features which is a perfect starting point for your further development.

JHipster can be found at https://www.jhipster.tech/ or in an online variant at https://start.jhipster.tech/. Since JHipster has been in development since 2013, it is a mature tool with a vivid community and available on Github and Gitter.im. Fun fact: They award a price for fixing bugs, called “bug-bounty” which can be between $100 and $500 depending on the difficulty to solve it.

What this blog post is about

At the time of writing this blog I worked with version 6.8.0 of JHipster. I want to show you how to set-up a simple microservice architecture as a scaffold for an e-commerce platform with JDL. As a first try, the application is deployed to docker. Later in the post you’ll find the deployment to Kubernetes and Heroku. The initial setup for JHipster can also be achieved with an interactive approach. But for all of these methods there is the need to install some software first.

Prerequisites

Recommended is an AdoptOpenJDK Java 11 (LTS) build. Also install Node.js in a LTS version (for now it is 12.16.3). To globally install JHipster enter:
npm install -g generator-jhipster
You can also use Yarn:
yarn global add generator-jhipster
JHipster will automatically install a wrapper for Maven or Gradle so it is not necessary to install them. If Git is installed, JHipster will try to commit the project to Git. For this example you also need Docker installed. For the moment I have Docker version 19.03.8 installed.

On your marks…

Open https://start.jhipster.tech/ in your browser, sign in and navigate to “Design Entities” and press “Create a new JDL Model”
design entities onlineFigure 1: Design Entities online

new jdl modelFigure 2: New JDL Model
If you open the JDL designer for the first time, a sample entity model appears combined with the according diagram. Just select all and delete all to get an empty workspace.

sample edit modelFigure 3: Sample entity model

Define applications and entities with JDL

For microservice architectures JHipster knows two application types: gateways and microservices.

  • A gateway handles web traffic and serves the frontend application. You can follow the Backends for Frontends pattern with this approach and build a gateway for every frontend technology that you want to serve.
  • Microservices handle the frontend requests as backend services, are stateless and several instances can be launched in parallel to cope with high traffic.

The first app we define is the frontend gateway using some defaults like Angular etc. Find the complete documentation for applications here. The next two apps are the microservices split in a service serving the product master-data and the other one serving the orders. The gateway uses all entities and all services use Kafka for messaging. Deployment is defined for using Docker.

The special case in this entity model is the user entity that is actually hidden by JHipster, which is expanded in a one-to-one relationship with necessary attributes for the customer. This only works if OAuth2 is specified as authenticationType. Only in this case a copy of the user record is copied from the authentication provider to the database when logging in.

Data transfer object can be used to enforce strong decoupling from the JPA-managed entities of an EntityManager. This makes it easier to implement additional business logic in the service classes.

Finally, meta information for the scrolling functionality of the product list is specified. It should be loaded lazily and can be browsed page by page. The microservice instruction specifies from which services entities can be obtained.

Here is the complete listing of the apps and entity definition:

application {
  config {
    baseName webStore
    applicationType gateway
    serverPort 9042
    authenticationType oauth2
    packageName	com.mycompany.store.web
    searchEngine elasticsearch
    serviceDiscoveryType eureka
    testFrameworks [protractor]
    languages [en, de]
    nativeLanguage en
	messageBroker kafka    
  }
  entities *
}

application {
  config {
    baseName storeService
    applicationType microservice
    serverPort 8083
    authenticationType oauth2
    packageName	com.mycompany.storeservice
    searchEngine elasticsearch
    serviceDiscoveryType eureka
    languages [en, de]
    nativeLanguage en
	messageBroker kafka 
	   
  }
  entities Product, Photo
}

application {
  config {
    baseName orderService
    applicationType microservice
    serverPort 8084
    authenticationType oauth2
    packageName	com.mycompany.order
    searchEngine elasticsearch
    serviceDiscoveryType eureka
    languages [en, de]
    nativeLanguage en
    messageBroker kafka    
  }
  entities SalesOrder, SalesOrderItem
}

deployment {
  deploymentType docker-compose
  appsFolders [storeService, orderService, webStore]
  dockerRepositoryName "joergriegel"
}

enum Gender {
   FEMALE, MALE, DIVERSE
}

entity Customer {
    name String required minlength(2)
    phoneNumber String
    gender Gender
    addressLine1 String
    addressLine2 String
    addressLine3 String
    addressLine4 String
    townCity String
    county String
    zip String
}

enum SalesOrderStatus {
    PENDING, CANCELLED, SHIPPED, COMPLETED
}

entity SalesOrder {
    salesOrderNumber String
    customerId String
    placed Instant
    cancelled Instant
    shipped Instant
    completed Instant
    status SalesOrderStatus
}

enum SalesOrderItemStatus {
    PENDING, DELIVERED, OUTOFSTOCK, COMPLAINED
}

entity SalesOrderItem {
    name String
    sku String
    taxable Boolean
    grosWeight Double
    shipped LocalDate
    delivered LocalDate
    status SalesOrderItemStatus
    quantity BigDecimal
    unitPrice BigDecimal
    amount BigDecimal
}

enum ProductStatus {
    ONSALE, LOCKED, OOUTOFSTOCK, INREPLENISHMENT
}

enum UnitOfMeasurement {
    PIECE, KILOGRAM, GRAM, LITER 
}

entity Product {
    name String required minlength(2)
    sku String required minlength(6)
    description String
    srp BigDecimal
    taxable Boolean
    salesUnit UnitOfMeasurement
    salesQuantity BigDecimal
    status ProductStatus
    grosWeight Double
    netWeight Double
    length Double
    width Double
    height Double
}

entity Photo {
    photo ImageBlob
} 

relationship ManyToOne {
    Customer{user(login)} to User
}

relationship OneToMany {
    SalesOrder{orderItems} to 
      SalesOrderItem{salesOrder(salesOrderNumber)}
    Product{photos} to Photo{product(name)}
}

// Use Data Transfer Objects (DTO)
dto * with mapstruct

// Set service options to all
service all with serviceClass

paginate Product with infinite-scroll

microservice Product, Photo with storeService
microservice SalesOrder, SalesOrderItem with orderService

This is the diagram for the resulting entity model:
Entity ModelFigure 4: Entity Model

Generate the code

Either you use the JDL Studio to edit the above JDL and press “Download text file of this JDL” or you copy the JDL into a file with the extension “jh”. If you press download the name of the file in your download directory will be “jhipster-jdl.jh”.
Download JDLFigure 5: Download JDL

JHipster internally uses Yeoman to generate code. In order to use the JDL generator just type in a terminal:
jhipster import-jdl
The generators are smart so that you can change models over and over again – no problem. Changing the database schema is no drama. They put Liquibase inside doing all the changesets necessary to bring schema changes from the sandbox to production.

After generating one of the apps, the gateway “webStore” with Angular 9 code has a nice Readme, a lot of docker-compose yml files and looks like this:
intellij ideaFigure 6: Intellij Idea

Two profiles “dev” and “prod” were generated. Now navigate to each directory of the apps and build production-ready code deployed on Docker:

./mvnw -ntp -Pprod verify jib:dockerBuild

Get set…

As you can see JHipster uses the Jib maven-plugin to build an image for each app. After you completed this three apps, you navigate to the directory “docker-compose” and start docker by typing:

docker-compose up -d

Make sure that you allow docker enough memory to cope with the size of the images. For me 10GB worked for this example.
docker settingsFigure 7: Docker Settings

docker ps should show 13 containers started:
docker psFigure 8: Docker ps

…Go

Open your browser on localhost:8080 and voilà. Your first JHipster microservice is up:
the applicationFigure 9: The Application
As you defined 2 possible languages, there is a drop down where you can choose another language.
language selectionFigure 10: Language Selection

localized applicationFigure 11: Localized Application

Login

Important: before you can use Keycloak, you have to add an entry in your etc/hosts:
127.0.0.1 keycloak
or else the redirection will not work for you. The reason for this is that Docker will use service names to reach services internally.

Login with admin/admin via Keycloak started in a container because you chose “oauth2” in the application definition.
loginFigure 12: Login
Once you signed in, Keycloak will provide you with SSO and handles all the token logic. For a production grade you still must modify the docker-compose to have it more robust and secure. The other predefined user is “user/user”. The only difference is that this user is not allowed to see or start administrative tasks from the menu. Keycloak makes it easy to fine-grain this role-based access control. If you need deeper knowledge or training on Keycloak don’t hesitate to contact us.

All the defined entities are shown in the menu and you first get the list and then can decide to create new entries in a form generated for the entity.
crud the entitiesFigure 13: CRUD the Entities

Relations are selectable using a combo-box. If you used a hint in the JDL what to display from the opposite entity like this: Customer{user(login)} to User, the combo will display the field “login” instead of the meaningless id.
edit customerFigure 14: Edit Customer

The list will look like the following figure with some entries. Don’t forget that this is only scaffolding, there is still a lot of work to do to get a nice-looking UI. But by then it is already a huge time advantage thanks to the use of JHipster.
customer listFigure 15: Customer List

Under the hood

What drives microservices developers the most is statistics about how the services behave, how healthy they are, and how one can easily implement malfunction analysis. With JHipster you are not left alone. The administrative menu shows some functions that must not be missing in any professional system. But in case your application won’t start would you lose this information? No – you have JHipster-Registry (already started with Docker) which provides the same information in an independent service. The default port for the registry is 8761.
administrationFigure 16: Administration

Gateway

gateway routesFigure 17: Gateway Routes
Have a look at the routes and see what services on which servers are up and how they were built.

Metrics

metricsFigure 18: Metrics
Have all parameters under control:

  • the JVM
  • HTTP requests
  • Endpoint requests
  • Cache statistics

Health

healthFigure 19: Health
See different aspects of your services and drill-down some health checks to detail level.

Configuration

ConfigurationFigure 20: Configuration
Look at all configuration properties and use a filter to find the desired setting.

Audits

auditsFigure 21: Audits
Find out who had a session against your system and when.

Logs

logsFigure 22: Logs
Track down the source of problems in your applications by adjusting the granularity of logging.

API

swagger webFigure 23: Swagger Web
swagger orderserviceFigure 24: Swagger OrderService
Study the whole Swagger documentation of your microservice architecture.

Eureka

In JHipster Registry even more information can be seen:
instancesFigure 25: Instances
instance historyFigure 26: Instance History

More Metrics

In complex environments you also have the possibility to find out more about the health of your system with the JHipster Console. The applications can be configured to forward their metrics to an external monitoring system where they can be graphed over time and analyzed. You can profit from the ELK stack to create dashboards and alerts. Just clone JHipster Console from Github, and from the bootstrap directory run docker-compose up. In every application-prod.yml or if you wish application-dev.yml in src/main/resources/config change the “enabled” values to true:
jhipster propertiesFigure 27: JHipster Properties

HTTP Routing

routing architectureFigure 28: Routing Architecture
This is how the routing looks like in this setup: the gateway handles frontend requests on 8080 and is securing all services with Keycloak and its tokens. Microservices handle the backend tasks and take care of the database operations. The registry discovers all services and collects information about them.The console provides deeper insight about inner behavior of the services.

Deployment

Kubernetes

As you learned from the previous steps you can deploy JHipster microservices in a docker environment. But you can also deploy on Kubernetes. First you have to install Kubernetes on your local machine if you want to try it out locally. Follow the guide here and install Minikube too. Start your Minikube by typing in a terminal window:
minikube start
in a terminal window enter the docker-compose directory, create a sub-directory (e.g. k8s) and navigate to it. To create all the necessary files to deploy on Kubernetes there is a generator available, just type:
jhipster kubernetes and answer the questions like this:

kubernetes generatorFigure 29: Kubernetes Generator
Follow the instructions, issue the commands and check your pods afterwards:
kubectl get pods

Heroku

Heroku is a cloud platform as a service supporting several programming languages. We can use it to deploy our little microservice architecture to the cloud. At first we have to install the Heroku CLI from here. When this is done, you have to create a free account. Once your e-mail address is confirmed, you can login from a terminal window with:
heroku login

As we need the service discovery in the cloud for microservices, we first must deploy a version of JHipster Registry to Heroku.
After successful deployment of the Registry, you can run the JHipster generator for Heroku in each directory (storeService, orderService and webStore) of our system:
jhipster heroku

Important: The deployment type for our apps must be “jar” not “git”.

Conclusion

JHipster creates a uniform application framework that can be expanded into a larger application. All activities that would otherwise take up a lot of valuable time. With JHipster the entry hurdles are lowered and the options are increased. JHipster unlocks the advantages of Spring Boot. With Docker support and AWS Elastic Beanstalk, it has become easy to develop cloud-native applications. JHipster is very mature. This allows you to optimally combine the strengths of Java and JavaScript in the development of web applications, so that the path to cloud-native applications is less rocky.

Jörg Riegel

I’m an IT consultant at codecentric in Karlsruhe and worked for a long period as CTO at an IT-company that I co-founded 1989. After painful experiences on the “New Market” in the early 2000s, I developed software for various companies dealing with ERP software and POS systems for retail. Before joining codecentric, I worked for a medium-sized company as chief architect to develop a fully model-driven business application generator based on Xtext. I studied electrical engineering at the University of Karlsruhe.

Comment

Your email address will not be published. Required fields are marked *