Microservices architecture is a method of developing software systems as a suite of independently deployable, small, modular services in which each service runs a unique process and communicates through lightweight mechanisms, often an HTTP-based API. Node.js is a popular choice for microservices due to its speed, scalability, and lightweight nature.
Microservices break down a monolithic application into smaller, independent services that focus on a single business capability. These services can be developed, deployed, and scaled independently.
microservices-architecture/
βββ auth-service/
βββ user-service/
βββ product-service/
βββ order-service/
βββ api-gateway/
βββ docker-compose.yml
const express = require('express');
const dotenv = require('dotenv');
const jwt = require('jsonwebtoken');
const bodyParser = require('body-parser');
dotenv.config();
const app = express();
app.use(bodyParser.json());
const users = [{ id: 1, username: 'admin', password: 'admin' }];
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '1d' });
res.json({ token });
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Auth service running on port ${PORT}`));
JWT_SECRET=supersecretkey
PORT=5000
const express = require('express');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
const app = express();
dotenv.config();
app.use(express.json());
const users = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
];
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Token missing' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
res.status(403).json({ error: 'Invalid token' });
}
};
app.get('/users', authMiddleware, (req, res) => {
res.json(users);
});
const PORT = process.env.PORT || 5001;
app.listen(PORT, () => console.log(`User service running on port ${PORT}`));
For synchronous communication, use HTTP REST calls (e.g., using Axios or fetch). For async or event-based messaging, use RabbitMQ or NATS.
const axios = require('axios');
const getUserData = async (token) => {
const res = await axios.get('http://localhost:5001/users', {
headers: { Authorization: `Bearer ${token}` }
});
return res.data;
};
An API Gateway acts as the entry point for client requests and routes them to appropriate services. You can implement it using Express.js or tools like Kong, NGINX, or Traefik.
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
app.post('/login', async (req, res) => {
const result = await axios.post('http://localhost:5000/login', req.body);
res.json(result.data);
});
app.get('/users', async (req, res) => {
const token = req.headers.authorization;
const result = await axios.get('http://localhost:5001/users', {
headers: { Authorization: token }
});
res.json(result.data);
});
app.listen(3000, () => console.log('API Gateway running on port 3000'));
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5000
CMD [ "node", "app.js" ]
version: '3'
services:
auth:
build: ./auth-service
ports:
- '5000:5000'
user:
build: ./user-service
ports:
- '5001:5001'
api:
build: ./api-gateway
ports:
- '3000:3000'
Use retry logic, circuit breakers (like with opossum), and graceful degradation to handle failed services.
In large-scale deployments, use tools like Consul, etcd, or service mesh solutions like Istio or Linkerd to enable dynamic service discovery.
To decouple services and handle communication asynchronously, use message queues like RabbitMQ or Kafka.
const amqp = require('amqplib');
const sendMessage = async () => {
const conn = await amqp.connect('amqp://localhost');
const ch = await conn.createChannel();
const queue = 'user_created';
await ch.assertQueue(queue);
ch.sendToQueue(queue, Buffer.from(JSON.stringify({ id: 1, name: 'John' })));
console.log('Message sent');
};
sendMessage();
You can enhance the API gateway with:
Automate your workflow with GitHub Actions, GitLab CI, or Jenkins:
Microservices allow scalable and maintainable architectures by isolating business logic and responsibilities. Node.js, with its non-blocking architecture and ecosystem support, is an ideal platform to build such systems. By implementing containerization, service communication, API gateways, message brokers, and centralized logging, you can build and manage robust microservices effectively.
A function passed as an argument and executed later.
Runs multiple instances to utilize multi-core systems.
Reusable blocks of code, exported and imported using require() or import.
nextTick() executes before setImmediate() in the event loop.
Starts a server and listens on specified port.
Node Package Manager β installs, manages, and shares JavaScript packages.
A minimal and flexible web application framework for Node.js.
A stream handles reading or writing data continuously.
It processes asynchronous callbacks and non-blocking I/O operations efficiently.
Node.js is a JavaScript runtime built on Chrome's V8 engine for server-side scripting.
An object representing the eventual completion or failure of an asynchronous operation.
require is CommonJS; import is ES6 syntax (requires transpilation or newer versions).
Use module.exports or exports.functionName.
Variables stored outside the code for configuration, accessed using process.env.
MongoDB, often used with Mongoose for schema management.
Describes project details and manages dependencies and scripts.
Synchronous blocks execution; asynchronous runs in background without blocking.
Allows or restricts resources shared between different origins.
Use try-catch, error events, or middleware for error handling.
Provides file system-related operations like read, write, delete.
Using event-driven architecture and non-blocking I/O.
Functions in Express that execute during request-response cycle.
A set of routes or endpoints to interact with server logic or databases.
Yes, it's single-threaded but handles concurrency using the event loop and asynchronous callbacks.
Middleware to parse incoming request bodies, like JSON or form data.
Copyrights © 2024 letsupdateskills All rights reserved