Microservices Architecture from Scratch and Demo

What are Microservices? Why we use them? How do they work? What are the examples of Microservice? What is the difference between API and Microservices? These are the common questions that arise for programmers. So, let's look at everything in an easily understandable way.

What are Microservices?

Microservices are both architecture and an approach to writing software. Microservices applications are broken into the smallest components and independent from each other (loosely coupled). So these tiny services communicate with each other through APIs. Each service has its server and is connected to the database separately.

Sample Microservices Architecture

In this picture, the Client application communicates with Products, Order and Shipping services through API calls. Each service has its database and each service runs on its server port. You can see that there is a dotted line between services. This means both these services are communicating between them with the help of API calls.

Why we use Microservices?

Before we dive into this topic, we should know the traditional approach used for building applications. It is called Monolithic Architecture. The Monolithic application describes a single-tiered software application in which different components are combined into a single program from a single platform. Here, multiple components share one database and run in one server. This architecture is easy to develop, deploy and scale. However, once the application becomes large and the team grows in size, this approach becomes more difficult. And it is extremely problematic to apply new technology in a monolithic application because then the entire application has to be rewritten. That’s why the Microservices concept comes into software development.

All the services can be deployed and updated independently, which gives more flexibility. A bug in one microservice has an impact only on a particular service and does not influence the entire application. Also, it is much easier to add new features to a microservice application than a monolithic one. Another advantage of the microservices approach is that each element can be scaled independently. So the entire process is more cost- and time-effective than with monoliths when the whole application has to be scaled even if there is no need for it. Also, every monolith has limits in terms of scalability, so the more users you acquire, the more problems you have with your monolith. Therefore, many companies, end up rebuilding their monolithic architectures. And it is easy to apply various technologies and frameworks for each microservice in one project. For example, we can use nodejs for customer service and springboot for order service. We can choose the technology according to our needs.

But still, microservices have some drawbacks. Since a microservices architecture is a distributed system, you have to choose and set up the connections between all the modules and databases. Also, as long as such an application includes independent services, all of them have to be deployed independently. Microservices architecture is a complex system of multiple modules and databases so all the connections have to be handled carefully. A multitude of independently deployable components makes testing a microservices-based solution much harder.

Let's build an application using Microservices Architecture in nodeJS, Express, and MongoDB

Technologies used in Demo

In this Demo part, we gonna use NodeJs, ExpressJs and MongoDB. So it is better you have basic knowledge about these technologies. Create Microservices Directory and create 3 subfolders(Customers, Books, Orders) in it. Then in each subfolder install the below dependencies.

npm install express body-parser nodemon mongoose

Express, is a back end web application framework for Node. js. The body-parser is a NodeJs body parsing middleware that is used to extract the entire body portion of an incoming request stream and exposes it on req.body. nodemon is a command-line interface (CLI) utility that wraps your Node app, watches the file system, and automatically restarts the process. Then connect mongoose with each server and run it.

In /book.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost:27017/library-book', {useNewUrlParser: true}, () => {
console.log("mongoose connected")
})
app.listen(3000, () =>{
console.log("Book Server start");
})

Book server is running on port 3000.

In /customer.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost:27017/library-customer', {useNewUrlParser: true}, () => {
console.log("mongoose connected")
})
app.listen(4000, () =>{
console.log("Customer Server start");
})

Customer server is running on port 4000.

In /order.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost:27017/library-order', {useNewUrlParser: true}, () => {
console.log("mongoose connected")
})
app.listen(4000, () =>{
console.log("Order Server start");
})

Order server is running on port 5000.

Now, we have to create a database model for each folder.

./BookModel.js

const mongoose = require("mongoose");
mongoose.model('Book',{
title:{
type:String,
require:true
},
author:{
type:String,
require:true
},
numberofPages:{
type:Number,
require:true
},
publisher:{
type:String,
require:true
}
})

./CustomerModel.js

const mongoose = require("mongoose");
mongoose.model('Cutomer',{
name:{
type:String,
require:true
},
age:{
type:String,
require:true
},
address:{
type:String,
require:true
}
})

./OrderModel.js

const mongoose = require("mongoose");
mongoose.model('Order',{
customerID:{
type:mongoose.SchemaTypes.ObjectId,
require:true
},
BookID:{
type:mongoose.SchemaTypes.ObjectId,
require:true
},
initialDate:{
type:Date,
require:true
},
deliveryDate:{
type:Date,
require:true
}
})

Then in /book.js connect MongoDB model with the server and add HTTP requests.

in /customer.js

in /order.js

Here is the fun part begins. Every service runs separately. So we have to connect services to communicate within them. When customer orders books, order document is generated in the database and it contains customerID and bookID. So we have to connect bookModel and CustomerModel with OrderModel. Here we use JS library called Axios which is used to make HTTP requests from node. js or XMLHttpRequests from the browser and it supports the Promise API that is native to JS ES6.

So in the order.js

Here we connect customer service to retrieve customer name and book service to retrieve the book name with the help of Axios library. So in our JSON response, it will give the customer name and book title of a particular order.

This is the small basic structure of Microservices in nodeJS. Generally, we don't use Microservices architecture for small applications. I hope this article gives you a basic introduction to MicroServices.

Here you can view the entire code.

Computer Engineering Student (University Of Peradeniya)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store