cost-check microservice

The first thing to mention is, at this time, we do not care about the delivery-handler or stock-check microservices. The definition above states that a microservices structures an application as a collection of loosely coupled services. Each one of our microservices is a service, and our application will be the collection of these microservices.

Open up your cost-check folder and run npm init -y to initialise a new project.

In your terminal run the following command:

npm install --save app-root-path express

This is not a tutorial on how to create a REST API or how to use express; so you should be comfortable with what these packages are before continuing.

Now lets set up our project structure by running the following commands:

$ mkdir routes

$ touch app.js

app.js will be our entry point; so let’s do that first.

"use strict"; const express = require('express'); const appRootPath = require('app-root-path'); const apiRouter = require(appRootPath + '/routes/apiRouter'); const port = 3002;

const app = express(); // Set the api path to be '/api' app.use('/api', apiRouter); app.listen(port, () => { console.log(`Listening on port ${port}`); });

This is a very simple express application. It listens on port 3002 and only accepts the API endpoints defined in apiRouter .

Now lets build apiRouter . Here we are going to mock some simple Database operations.

"use strict"; const express = require('express'); const router = express.Router();

const allItems = [ {id: 1,name: 'cheese',price: 1.50}, {id: 2,name: 'bread',price: 1}, {id: 3,name: 'coffee',price: 4.75}, {id: 4,name: 'tea bags',price: 6.24} ]

router.get('/getAll', (req, res) => { res.json({data: allItems}); }); router.get('/getById/:id', (req, res) => { res.json({data: allItems.find(element => element.id == req.params.id)}); }); router.get('/getOne', (req, res) => { let property = Object.keys(req.query); res.json({data: allItems.find(element => element[property] == req.query[property])}); }); module.exports = router;

None of this should be difficult to understand, if you know how to make an express app, so I’m going to move on. That’s it for our cost-check microservice. Just a simple service that will return item(s) and their costs.

stock-check microservice

This is going to be almost identical to the cost-check microservice, as it’s the same concept, but instead of the cost of an item it will return the number of items in stock. Make sure you run npm init -y and install the required dependencies like the last step.

// app.js

"use strict"; const express = require('express'); const appRootPath = require('app-root-path'); const apiRouter = require(appRootPath + '/routes/apiRouter');

const port = 3010; const app = express();

// Set the api path to be '/api' app.use('/api', apiRouter); app.listen(port, () => { console.log(`Listening on port ${port}`); }); // routes/apiRouter.js

"use strict"; const express = require('express'); const router = express.Router();

const allItems = [ {id: 1,name: 'cheese',quantity: 12}, {id: 2,name: 'bread',quantity: 125}, {id: 3,name: 'coffee',quantity: 0}, {id: 4,name: 'tea bags',quantity: 2} ] router.get('/getAll', (req, res) => { res.json({data: allItems}); });

router.get('/getById/:id', (req, res) => { res.json({data: allItems.find(element => element.id == req.params.id)}); });

router.get('/getOne', (req, res) => { let property = Object.keys(req.query); res.json({data: allItems.find(element => element[property] == req.query[property])}); }); module.exports = router;

delivery-handler microservice

And finally our delivery-handler microservice, that will calculate the cost of delivery depending on which country the user is in. Make sure you run npm init -y and install the required dependencies like the last step.

// app.js

"use strict"; const express = require('express'); const appRootPath = require('app-root-path'); const apiRouter = require(appRootPath + '/routes/apiRouter'); const port = 3020; const app = express();

// Set the api path to be '/api' app.use('/api', apiRouter); app.listen(port, () => { console.log(`Listening on port ${port}`); }); // routes/apiRouter.js

"use strict"; const express = require('express'); const router = express.Router(); const allItems = [ {id: 1,country: 'UK',quantity: 5}, {id: 2,country: 'USA',quantity: 10}, {id: 3,country: 'Portugal',quantity: 12}, {id: 4,country: 'China',quantity: 20} ] router.get('/getAll', (req, res) => { res.json({data: allItems}); }); router.get('/getById/:id', (req, res) => { res.json({data: allItems.find(element => element.id == req.params.id)}); }); router.get('/getOne', (req, res) => { let property = Object.keys(req.query); res.json({data: allItems.find(element => element[property] == req.query[property])}); }); module.exports = router;

That’s it

You’ve created three microservices. Yes really! But no, that’s not the end of the article. Now I’ll show you how to utilise them.

In your microservice-tutorial folder, create another folder called microservie-app , run npm init -y and npm install — save express app-root-path like before.

Now open up three different terminals and run node app.js on the three microservices we made in the previous steps. You should see Listening on port [port] once you’ve run this command, to indicate that the server is up and running.

We now have three running microservices; all running independently of each other. The next step is we’re going to use them. In your microservice-app directory created a config directory and a config.json underneath it:

// config/config.json

{ "costCheck": "http://localhost:3002", "deliveryHandler": "http://localhost:3020", "stockCheck": "http://localhost:3010" }

There is nothing special going on here; we’re running our microservices on localhost and they are running on the ports that we defined in each microservice. We’ll use these URL’s to interact with them.

Next for our app.js file.

// app.js

"use strict"; const express = require('express'); const appRootPath = require('app-root-path'); const axios = require('axios'); const { costCheck, deliveryHandler, stockCheck } = require(appRootPath + '/config/config.json'); const port = 9443; const app = express();

/** Application routes */ app.get('/checkOne', (req, res) => { Promise.all([ axios.get(`${costCheck}/api/getOne?${req._parsedUrl.query}`), axios.get(`${stockCheck}/api/getOne?${req._parsedUrl.query}`), axios.get(`${deliveryHandler}/api/getOne?${req._parsedUrl.query}`) ]).then(values => { res.json({data: values.map(resp => resp.data)}); }); }); app.listen(port, () => { console.log(`Listening on port ${port}`); });

At this point in time; we should forget that we built the microservices earlier on. All we know at this point is we have three microservices, with three REST API’s, that we can interact with.

And that’s exactly what we’re doing. Start this app by running node app.js , open a browser, and go to http://localhost:9443/checkOne?name=cheese&country=UK if it all worked like it should you should now see your JSON object…

That really is it. You’ve now made a very simple application, that utilises three microservices.

Why though?

That’s an easy question to answer. All the bits of our application (Cost checker, delivery handler and stock checker) are now self-contained. They are all currently written in Node, but if we wanted to change our cost-check microservice to Java; we could without breaking/re-writing the whole application.

It also means:

It’s easier to deploy. We only need to deploy the microservice we’re making changes to.

It’s more scalable. If cost-check is extremely CPU intensive, but uses very little RAM, and stock-check is extremely RAM intensive, but uses very little CPU, we can account for that with each container we build. If we weren’t using microservices; we’d have to deploy each container with a lot of RAM and CPU to account for both.

is extremely CPU intensive, but uses very little RAM, and is extremely RAM intensive, but uses very little CPU, we can account for that with each container we build. If we weren’t using microservices; we’d have to deploy each container with a lot of RAM and CPU to account for both. It’s more productive. Each microservice can be written in any language. So if all of our Node developers are busy for 6 months, but we desperately need a new service and our Python developers are free, they can create it and expose the REST API the same way.

Feel free to reach out with any comments/questions.