Building Microservices Using Node.js: A Step-by-Step Guide

Because microservices architecture is flexible, scalable, and easy to maintain, it is becoming increasingly popular for creating large-scale systems. In contrast to monolithic designs, which combine all functionality into a single codebase, microservices divide an application into more manageable, separate services that may interact with one another. In this blog article, we will look at how to create microservices using Node.js, a well-liked runtime environment for building effective and scalable applications. Let’s learn about Microservice using Node.js.

What are Microservices?

The architectural approach known as “microservices” is characterized by creating individual services as separate, loosely connected entities inside an application. Every service may be deployed individually, operates in its process, and usually carries out a single business function. Services can exchange messages via messaging queues or lightweight protocols like HTTP/REST.

Key benefits of microservices include:
  • Scalability: Individual services can be scaled based on demand.
  • Resilience: If one service fails, others remain unaffected.
  • Maintainability: Small, independent services are easier to maintain and update.

Why Microservices Using Node.js?

Node.js is well-suited for microservices architecture because:

  1. Non-blocking I/O: Node.js is designed to handle asynchronous, event-driven operations, which is crucial for microservices that must handle multiple services and data flows efficiently.
  2. Lightweight and fast: Node.js is known for its lightweight, quick, and scalable nature, making it a great choice for microservice-based systems.
  3. NPM Ecosystem: The Node Package Manager (NPM) offers a wide range of libraries that make building microservices quicker and easier.

Steps to Build Microservices with Node.js

1. Setting Up the Environment

First, ensure you have Node.js and NPM installed. To verify, run:

node -v
npm -v

Create a directory for your project:

mkdir microservices-demo
cd microservices-demo

Initialize the project:

npm init -y

Install the necessary packages, such as Express for handling HTTP requests and Docker (if needed) for containerizing services:

npm install express
2. Design the Microservices

Before diving into code, you must plan the services you’ll build. For this demo, let’s create two microservices:

  • User Service: Manages user-related data.
  • Order Service: Manages orders placed by users.

Each service will run independently and communicate with each other via REST APIs.

3. Building the User Service

Let’s start by creating the User Service. Create a folder named user-service and inside it, initialize a basic Express server:

mkdir user-service
cd user-service
npm init -y
npm install express

Create server.js:

const express = require('express');
const app = express();
app.use(express.json());

const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
];

// Get all users
app.get('/users', (req, res) => {
    res.json(users);
});

// Get user by ID
app.get('/users/:id', (req, res) => {
    const user = users.find(u => u.id == req.params.id);
    if (user) {
        res.json(user);
    } else {
        res.status(404).json({ message: 'User not found' });
    }
});

const PORT = 3000;
app.listen(PORT, () => {
    console.log(`User service running on port ${PORT}`);
});

Run the service:

node server.js

The User Service will now be running on localhost:3000.

4. Building the Order Service

Now, let’s create the Order Service. Create a folder order-service:

mkdir order-service
cd order-service
npm init -y
npm install express

Create server.js:

const express = require('express');
const app = express();
app.use(express.json());

const orders = [
    { id: 1, userId: 1, product: 'Laptop' },
    { id: 2, userId: 2, product: 'Phone' }
];

// Get all orders
app.get('/orders', (req, res) => {
    res.json(orders);
});

// Get order by user ID
app.get('/orders/:userId', (req, res) => {
    const userOrders = orders.filter(order => order.userId == req.params.userId);
    if (userOrders.length > 0) {
        res.json(userOrders);
    } else {
        res.status(404).json({ message: 'No orders found for this user' });
    }
});

const PORT = 3001;
app.listen(PORT, () => {
    console.log(`Order service running on port ${PORT}`);
});

Run the service:

node server.js

The Order Service will now be running on localhost:3001.

5. Communication Between Services

In a microservices architecture, services need to communicate. One common way is via HTTP REST. For instance, if the Order Service needs to fetch user details from the User Service, it can make a REST API call.

Here’s how you can modify the Order Service to fetch user details:

In server.js of the Order Service:

const axios = require('axios');

// Get order by user ID with user details
app.get('/orders/:userId', async (req, res) => {
    const userOrders = orders.filter(order => order.userId == req.params.userId);
    if (userOrders.length > 0) {
        try {
            const userResponse = await axios.get(`http://localhost:3000/users/${req.params.userId}`);
            const user = userResponse.data;
            res.json({
                user: user,
                orders: userOrders
            });
        } catch (error) {
            res.status(500).json({ message: 'Error fetching user details' });
        }
    } else {
        res.status(404).json({ message: 'No orders found for this user' });
    }
});

Here, we used axios to make an HTTP request to the User Service to fetch user details. To install axios, run:

npm install axios

Now, when you access the Order Service, it will include the user details along with their orders.

6. Containerizing Services with Docker

Once your services are built, containerization with Docker ensures that they run consistently across different environments.

Create a Dockerfile for each service:

For User Service (user-service/Dockerfile):

FROM node:14
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

For Order Service (order-service/Dockerfile):

FROM node:14
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3001
CMD ["node", "server.js"]

Build and run the containers:

docker build -t user-service ./user-service
docker build -t order-service ./order-service
docker run -p 3000:3000 user-service
docker run -p 3001:3001 order-service

Conclusion

By dividing services into smaller, independent components, Node.js microservices enable you to build scalable, maintainable apps. You can build effective microservices that scale on demand and can interact with ease by using tools like Docker and frameworks like Express. This design is perfect for contemporary, large-scale applications because it provides more flexibility and robustness.

Leave a Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.