Frank Joseph I'm an innovative software engineer and technical writer passionate about the developer community. I'm interested in building applications that run on the internet.

Building microservices with Node.js

7 min read 2099

Node Microservices

Editor’s note: This article was last updated on 19 October 2022 to include additional information about microservice communication. 

In early software development, best practice involved tightly coupling all of the software’s components in what is known as a monolithic application. However, monolithic applications require extra effort to respond to changes in the system. If any particular component develops a fault, the entire system is affected.

Nowadays, we can solve this problem by using microservices, which allow us to build our software components separately. A fault in one component won’t affect the functionality of the entire software product.

In this article, we’ll explore microservices, learning how to implement a microservice with Node.js and discussing how microservices are changing the practice of software development. Let’s get started!

To follow along with this article, you’ll need the following:

  • Node.js installed on your computer
  • Basic knowledge of JavaScript and Node.js

Table of contents

Microservices vs. monolithic applications

Understanding monolithic applications

A monolithic application is a single-tiered application in which all components are composed as one unit.

Imagine you’re building a library management system, and all of the components, like books and users, and their respective services and databases are fused together as one unit. A fault in any one component will require bringing down the entire system to correct the error.

For this reason, monolithic applications are neither flexible nor easily scalable; you cannot build features concurrently or achieve continuous deployment. While monolithic applications are not cost-effective to manage, they are cost-effective to build. Therefore, developers recognized the need to create a system in which one faulty component wouldn’t affect the entire software system.

Understanding microservices

Microservices became necessary due to the shortcomings of the monolithic pattern of software development. In a microservice, each software application feature is separated from the other, in most cases with their respective servers and databases. Applications built with this kind of architecture are loosely coupled, also referred to as distributed applications.

Imagine we’re building an ecommerce store. We’ll need models for a payment feature, cart, customers, admin, and order. Each of these features will have its own separate servers and databases.

Our ecommerce microservices will communicate with each other using the REST API framework. Because we’ll develop our store features independently from each other, if our system develops a fault, we can easily identify which feature to debug and avoid having to bring down the entire application.

In contrast to monolithic applications, applications developed using microservices are scalable. You can use any programming language to develop a microservice; in fact, you can use different languages to develop different features in a microservice application.

Overall, microservices offer a better developer experience. A new developer joining the team won’t have to understand the entire codebase, but rather just the features they are working on, increasing overall productivity. Lastly, unit testing is encouraged in microservices; you can write a unit test to test any particular functionality.

It’s important to keep in mind that building a microservice requires expertise because integration and end-to-end testing can be very challenging. Additionally, microservices can become very bulky, resulting in high maintenance costs. Lastly, it’s not always easy to migrate software already developed using monolithic architecture to a microservice, and it can be challenging for applications to locate each other within a complex network.

Communication between microservices

Choosing a microservice architectural pattern comes with some challenges; one of these is service-to-service communication. Services are a loosely coupled part of an application that together contribute to the application’s overall performance.



To achieve effective performance, there has to be a means of communication between the microservices. In a microservice application, communication is made possible through an inter-service communication protocol like HTTP(s), gRPC, or message brokers.

Let’s review some of the ways in which services establish communication in a microservice architecture.

HTTP communication

HTTP communication is a kind of synchronous communication pattern where a service is dependent on another to perform:

HTTP Communication Request Response Diagram

The image above represents the HTTP request-response cycle, where the client makes a request and waits for a response from the server-side application.

Event-driven communication pattern

The event-driven communication pattern entails an interaction between a service provider and a service consumer. The service consumer requires a resource from an external source. It then performs some computations and relays the response to the client:

event-driven-communication-pattern-diagram

Using Node.js for our microservice

You can use any programming language to develop a microservice, like Java, C#, or Python, but Node.js is an outstanding choice for a few reasons.

For one, Node.js uses an event-driven architecture and enables efficient, real-time application development. Node.js single-threading and asynchronous capabilities enable a non-blocking mechanism. When building a microservice with Node.js, developers will experience an uninterrupted flow and enjoy Node’s speed, scalability, and easy maintenance.

Build a simple microservice application with Node.js

Install dependencies

To illustrate how to develop microservices with Node.js, we’ll use the OpenWeather API service. First, create a free account.

Create a new folder on your computer, preferably on your desktop for easy access, and name it weathermicroservice. Open weathermicroservice in your code editor and confirm that you have Node.js installed on your computer by running the command below:

node -v

If Node.js is not installed, go ahead and download it. In weathermicroservice, run the command below to initialize the package.json:

Run npm init or npm init -y

With npm init, you can customize the setting or fields to create the package.json file. On the other hand, npm init -y uses the default setting or fields to create the package.json file.

Now, let’s install the required dependencies with the command below:

run npm install express nodemon body-parser

Your package.json file should look similar to the screenshot below:

Package JSON Nodejs Microservice

Directly inside the main folder, create a file called server.js. Inside, write the following code:

const express = require("express");
const bodyParser = require("body-parser")

const aboutRouter = require("./routes/about");
const weatherRouter = require("./routes/weather");

const PORT = 3000;
const HOST_NAME = "localhost";

const app = express();
app.use(express.static("client"));
app.use(bodyParser.urlencoded({extended: true}));

app.use("/weather", weatherRouter);
app.use("/about", aboutRouter);


app.listen(PORT, HOST_NAME, ()=>{
    console.log(`Server running at ${HOST_NAME}:${PORT}`)
})

server.js is the main file for our basic weather microservice app, as indicated in our package.json file. We’ll create another folder inside the weathermicroservice folder named routes.

Inside the routes folder, create two files named about.js and weather.js. Inside the about.js file, write the following code:

const express = require("express");
const properties = require("../package.json");

const aboutRoute = express.Router();

aboutRoute.get("/", (req, res)=>{
    const aboutInfo ={
        name: properties.name,
        description: properties.description,
        author: properties.author
    }
    res.json(aboutInfo)
})

module.exports = aboutRoute

In the code above, we first require or import the express module, followed by the package.json file, which we assign to the variable named properties.

Then, we invoke the express.Router function. Finally, we implement our GET route, which returns an aboutInfo  containing information about our application, as contained in the package.json file. Remember, we imported our package.json file on the second line of code in the about.js file.


More great articles from LogRocket:


Creating the client side

Now that we’re done with the about.js route module, we’ll create the route that handles the weather info request. Before we do that, let’s create the client-side of our application.

First, we’ll create a basic HTML file that receives user input. Under your main project folder, create a folder called client. Inside it, create an index.html file and add the code below to it:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weather App</title>
</head>
<body>
    <h1>A basic Weather app microservice</h1>
    <p>Enter your details to get weather Info </p>
    <form action="/weather" method="post">
        <label for="cityInput">City name: </label>
        <input type="text" name="cityName" placeholder="Enter name of your city" id="cityInput">
        <label for="unitInput">Unit</label>
        <input type="text" name="unit" placeholder="Enter unit in metric" id="unitInput">
        <button type="submit">submit</button>
    </form>

</body>
</html>

This is a basic HTML form that allows you to input your city name and metric units, as well as submit the inputs as a POST request to the weather route.

To create the route that handles the weather info, create a file called weather.js inside the route folder and add the following code to it:

const express = require("express");
const https = require('https')

const weatherRoute = express.Router();
weatherRoute.get("/", (req, res)=&gt;{
    res.sendFile(__dirname, + "index.html")   
})

weatherRoute.post("/", (req, res)=&gt;{
        const city = req.body.cityName
        const appiKey = "Your API Key" 
        const unit = req.body.unit

        const url = "https://api.openweathermap.org/data/2.5/weather?q="+ city + "&amp;appid="+appiKey+"&amp;units="+unit+""
        https.get(url, (response)=&gt;{
            response.on("data", (chunk)=&gt;{
                const responseData = JSON.parse(chunk);
                const temperature = responseData.main.temp;
                const weatherDes = responseData.weather[0].description;
                const icon = responseData.weather[0].icon;
                const imageURL = "http://openweathermap.org/img/wn/"+ icon + "@2x.png";
                const cityName = responseData.name;
                res.write(`&lt;h1&gt;The weather is ${temperature} degree celsius in ${cityName} and the description is ${weatherDes} &lt;/h1&gt;`)
                res.write("&lt;img src="+ imageURL +"&gt;")
                res.send()
            })
        })
})
module.exports = weatherRoute

First, we required Express and the native https Node.js modules. We then created an instance of Express and invoked the Express router function. Using the Express instance, we created our first route that sends a response to the client when a request hits the server.

The response should serve a basic form like the one below to the client:

Basic Weather App Microservice

res.sendFile(__dirname, + "index.html")

We then send the index.html file to the client. When the submit button is clicked, a POST request is made by the client to the server. The server accesses the body of the request through the request object and saves it into the variables:

const city = req.body.cityName
const unit = req.body.unit

Now that we have these parameters, we can easily access the OpenWeather API. The URL below helps us connect to the Weather API:

const url = "https://api.openweathermap.org/data/2.5/weather?q="+ city + "&amp;appid="+appiKey+"&amp;units="+unit+""

Using the Node.js native https module, we perform a GET request to the Weather API. We then parse the data from the response body into an object using JSON.parse().

We’ll need the following as part of the response data for our application:

  • Temperature
  • Weather description: weatherDes
  • Icon
  • Image
  • City Name

Finally, we used the res.write function from the Node.js writeable interface to send the response back to the client. Now, to run this application, run the following command in your root folder:

node server.js

On your console, you should have something similar to the image below:

Nodejs Microservice Console Image

Then, go to your browser, Chrome preferably, and make a request to port 3000:

Chrome Request Port 3000

You should have a response like the one below:

Basic Weather Microservice App

In the City name field, type in the name of your city, and in the Unit field, type in metric to convert the default temperature unit to celsius. The default temperature unit in the Weather API is Kelvin.

If you do everything correctly, then you have a response with the temperature reading in your city, and the icon to represent it:

Final Microservice Weather Application

 

The image above is the output I received representing the temperature reading in my city.

Conclusion

In this tutorial, we learned about the important differences between microservices and monolithic applications. We learned why Node.js is a great choice for building microservices, and we ran through an example using the OpenWeather API.

Using a microservice offers flexibility and performance benefits that can’t be achieved with a monolithic application. The event-driven architecture of Node.js makes it a perfect choice for microservices, being fast, highly scalable, and easy to maintain.

200’s only Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket. LogRocket Network Request Monitoringhttps://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.
Frank Joseph I'm an innovative software engineer and technical writer passionate about the developer community. I'm interested in building applications that run on the internet.

9 Replies to “Building microservices with Node.js”

  1. Bro, you should attach your website and linkedin profile to your page. That way people can reach you with opportunties.

  2. Toi bad the most important part is not described. How do multiples microservice interact with each other. For exemple you call an endpoint this endpoint retreive data and call 2 other micro services that have coupled data in another db

  3. For a Node.js article, this felt pretty dated and out of touch. I guess my biggest gripe is that you’re promoting the use of request (which has been deprecated for a while now) but also some of the conventions used aren’t exactly the best. I also wish you’d explain microservices more in depth. Just some constructive criticism

  4. The code snippets are all with mistakes. I don’t know why, but LogRocket has all the best tutorials to start with but with a lot of mistakes. This is very bad

      1. In the server.js file, the line app.use(express.static(“client”)) should be removed. It is not needed in this code snippet and will cause an error.

        In the weather.js file, the line weatherRoute.get(“/”, (req, res)=>{res.sendFile(__dirname, + “index.html”)} will cause an error because __dirname is a path, and res.sendFile expects a file path as its first argument, but it is being concatenated with a string “index.html”. It should be like this res.sendFile(__dirname + “/index.html”)

        In the weather.js file, the line const appiKey = “Your API Key” is hardcoded and it should be replaced with a valid API key otherwise the application will not work as expected.

        In the weather.js file, the line const url = “https://api.openweathermap.org/data/2.5/weather?q=”+ city + “&appid=”+appiKey+”&units=”+unit+”” should use encodeURI function to encode the url parameters, to avoid any issues with special characters or spaces in the parameters.

Leave a Reply