Microservices in Node.js
What are Microservices?
Microservices is an architectural style where an application is composed of small, independent services that communicate over well-defined APIs.
Basic Microservice
// user-service.js
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
});
app.post('/users', async (req, res) => {
const user = await User.create(req.body);
res.status(201).json(user);
});
app.listen(3001, () => {
console.log('User service running on port 3001');
});Service Communication
HTTP/REST
// order-service.js
const axios = require('axios');
app.post('/orders', async (req, res) => {
try {
// Call user service
const user = await axios.get(`http://user-service:3001/users/${req.body.userId}`);
// Call product service
const product = await axios.get(`http://product-service:3002/products/${req.body.productId}`);
// Create order
const order = await Order.create({
userId: user.data.id,
productId: product.data.id,
total: product.data.price
});
res.status(201).json(order);
} catch (err) {
res.status(500).json({ error: err.message });
}
});Message Queue (RabbitMQ)
const amqp = require('amqplib');
// Publisher
async function publishMessage(queue, message) {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
await channel.assertQueue(queue);
channel.sendToQueue(queue, Buffer.from(JSON.stringify(message)));
await channel.close();
await connection.close();
}
// Consumer
async function consumeMessages(queue, callback) {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
await channel.assertQueue(queue);
channel.consume(queue, (msg) => {
const data = JSON.parse(msg.content.toString());
callback(data);
channel.ack(msg);
});
}
// Usage
await publishMessage('orders', { orderId: 123, userId: 456 });
await consumeMessages('orders', (order) => {
console.log('Processing order:', order);
});API Gateway
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// Route to user service
app.use('/api/users', createProxyMiddleware({
target: 'http://user-service:3001',
changeOrigin: true
}));
// Route to product service
app.use('/api/products', createProxyMiddleware({
target: 'http://product-service:3002',
changeOrigin: true
}));
// Route to order service
app.use('/api/orders', createProxyMiddleware({
target: 'http://order-service:3003',
changeOrigin: true
}));
app.listen(3000, () => {
console.log('API Gateway running on port 3000');
});Service Discovery
const consul = require('consul')();
// Register service
async function registerService() {
await consul.agent.service.register({
name: 'user-service',
address: 'localhost',
port: 3001,
check: {
http: 'http://localhost:3001/health',
interval: '10s'
}
});
}
// Discover service
async function discoverService(serviceName) {
const result = await consul.health.service(serviceName);
return result[0].Service;
}Circuit Breaker
const CircuitBreaker = require('opossum');
const options = {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000
};
async function callUserService(userId) {
const response = await axios.get(`http://user-service:3001/users/${userId}`);
return response.data;
}
const breaker = new CircuitBreaker(callUserService, options);
breaker.fallback(() => ({ id: null, name: 'Unknown' }));
breaker.on('open', () => console.log('Circuit opened'));
breaker.on('halfOpen', () => console.log('Circuit half-open'));
breaker.on('close', () => console.log('Circuit closed'));
// Usage
const user = await breaker.fire(userId);Docker Compose
version: '3.8'
services:
user-service:
build: ./user-service
ports:
- "3001:3001"
environment:
- DATABASE_URL=mongodb://mongo:27017/users
depends_on:
- mongo
product-service:
build: ./product-service
ports:
- "3002:3002"
environment:
- DATABASE_URL=mongodb://mongo:27017/products
depends_on:
- mongo
order-service:
build: ./order-service
ports:
- "3003:3003"
environment:
- DATABASE_URL=mongodb://mongo:27017/orders
depends_on:
- mongo
api-gateway:
build: ./api-gateway
ports:
- "3000:3000"
depends_on:
- user-service
- product-service
- order-service
mongo:
image: mongo:latest
ports:
- "27017:27017"Best Practices
- Single responsibility per service
- Independent deployment
- Decentralized data management
- API gateway for routing
- Service discovery
- Circuit breakers for resilience
- Monitoring and logging
Interview Tips
- Explain microservices: Independent, loosely coupled services
- Show communication: HTTP, message queues
- Demonstrate API gateway: Centralized routing
- Discuss patterns: Circuit breaker, service discovery
- Mention challenges: Distributed transactions, debugging
Summary
Microservices architecture splits applications into small, independent services. Communicate via HTTP/REST or message queues. Use API gateway for routing, service discovery for location, circuit breakers for resilience. Deploy with Docker/Kubernetes.
Test Your Knowledge
Take a quick quiz to test your understanding of this topic.