In the ever-evolving landscape of software development, two groundbreaking architectural styles, microservices, and micro frontends, have emerged as transformative paradigms. These methodologies have been redefining the way modern applications are built and deployed. Embracing the principles of modularity, scalability, and flexibility, both microservices and micro frontends have become favored choices among development teams worldwide.
Whether you are a seasoned developer or just beginning your journey into the world of software architecture, this guide aims to equip you with a comprehensive understanding of microservices and micro frontends, and how they can elevate your application development to new heights.
What are Microservices?
Microservices is an architectural style where a monolithic application is divided into several small, loosely coupled, and independent services. All these microservices work together to form a larger system. Each service in a microservices architecture represents a specific business capability and operates as a separate unit with its own database and logic.
Microservices Tutorial
Step 1: Setting Up the Project
Create a new folder for your project and initialize a new Node.js project. Open a terminal and run the following commands:
mkdir microservices-tutorial
cd microservices-tutorial
npm init -y
Step 2: Install Dependencies
We will use Express.js and Axios for this tutorial. Install them using npm:
npm install express axios
Step 3: Create Microservices
For this tutorial, we'll create two microservices: a "users" service and an "orders" service. The "users" service will handle user-related operations, while the "orders" service will handle order-related operations.
Create two folders, "users" and "orders," inside the main project folder. Inside each folder, create an index.js
file.
Step 4: Implement Microservices
Let's start by implementing the "users" service. Open the users/index.js file and add the following code:
const express = require('express');
const app = express();
const port = 3000;
app.get('/users', (req, res) => {
const users = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' },
{ id: 3, name: 'Bob Johnson' },
];
res.json(users);
});
app.listen(port, () => {
console.log('Users service is running on port ' + port);
});
Now, let's implement the "orders" service. Open the orders/index.js
file and add the following code:
const express = require('express');
const app = express();
const port = 4000;
app.get('/orders', (req, res) => {
const orders = [
{ id: 1, product: 'Product A' },
{ id: 2, product: 'Product B' },
{ id: 3, product: 'Product C' },
];
res.json(orders);
});
app.listen(port, () => {
console.log('Orders service is running on port ' + port);
});
Step 5: Communicating Between Microservices
In this step, we will use Axios to make HTTP requests from one microservice to another. We'll modify the "users" service to fetch orders from the "orders" service.
Open the users/index.js
file again and add the following code:
const express = require('express');
const axios = require('axios');
const app = express();
const port = 3000;
const ordersServiceURL = 'http://localhost:4000';
app.get('/users', async (req, res) => {
try {
const response = await axios.get(`${ordersServiceURL}/orders`);
const orders = response.data;
const users = [
{ id: 1, name: 'John Doe', orders: orders.slice(0, 2) },
{ id: 2, name: 'Jane Smith', orders: orders.slice(1, 3) },
{ id: 3, name: 'Bob Johnson', orders: orders.slice(0, 1) },
];
res.json(users);
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(port, () => {
console.log('Users service is running on port ' + port);
});
Step 6: Run the Microservices
To run the microservices, open two separate terminals, navigate to the project folder, and run the following commands:
For the "users" service:
cd users
node index.js
For the "orders" service:
cd orders
node index.js
Step 7: Test the Microservices
Open your web browser or use a tool like Postman to test the microservices.
To test the "users" service, navigate to http://localhost:3000/users. It should return a list of users along with their associated orders.
To test the "orders" service, navigate to http://localhost:4000/orders. It should return a list of orders.
Congratulations! You've successfully created a basic microservices architecture using Node.js, Express.js, and Axios, where two microservices communicate with each other to fulfill a user request.
What are Micro Frontends?
Micro Frontends is a web development architectural pattern that extends the principles of microservices to the frontend of web applications. It involves breaking down the user interface of a web application into smaller, loosely coupled, and independently deployable frontend modules. Each module represents a distinct feature or functionality of the application and can be developed, tested, and deployed independently.
Micro Frontends Tutorial
Let's see how micro frontends work practically with a simple tutorial.
In this example, we will use Express.js to create a server that serves the individual microfrontends as static files. We also use the http-proxy-middleware library to proxy requests to the appropriate microfrontend based on the URL path. Let's get going!!!
Step 1: Set Up the Microfrontend Architecture
Create a new directory for your project and initialize a new Node.js project:
mkdir microfrontend-example
cd microfrontend-example
npm init -y
Step 2: Install Dependencies
Install the required dependencies for your microfrontend project:
npm install express
npm install express-http-proxy
Step 3: Create the Microfrontends
In this tutorial, we'll create two microfrontends: frontend1
and frontend2
.
Inside the project directory, create a frontend1
directory with an index.html
file:
<!-- frontend1/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Frontend 1</title>
</head>
<body>
<h1>Frontend 1</h1>
</body>
</html>
Similarly, create a frontend2
directory with an index.html file:
<!-- frontend2/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Frontend 2</title>
</head>
<body>
<h1>Frontend 2</h1>
</body>
</html>
Step 4: Create the Microfrontend Server
Create a new file named server.js
in the project root directory:
// server.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// Serve frontend1
app.use('/frontend1', express.static('frontend1'));
// Serve frontend2
app.use('/frontend2', express.static('frontend2'));
// Proxy requests to the appropriate microfrontend
app.use('/microfrontend1', createProxyMiddleware({ target: 'http://localhost:3000/frontend1', changeOrigin: true }));
app.use('/microfrontend2', createProxyMiddleware({ target: 'http://localhost:3000/frontend2', changeOrigin: true }));
// Start the server
app.listen(3000, () => {
console.log('Microfrontend server started on port 3000');
});
Step 5: Start the Microfrontend Server
In the terminal, run the following command to start the microfrontend server:
node server.js
Step 6: Access the Microfrontends
Open your browser and visit http://localhost:3000/microfrontend1 to see frontend1, and http://localhost:3000/microfrontend2 to see frontend2.
Congratulations! You have successfully created a simple microfrontend setup using Node.js.
When to use Micro Frontends?
Micro frontends and microservices are architectural patterns used to build scalable and modular applications, but they address different concerns and are suitable for different scenarios.
Micro frontends are used when you have a complex web application that requires multiple teams to work independently on different parts of the user interface. By breaking the frontend into smaller, self-contained modules, each team can develop and deploy their features separately, enabling faster development cycles and easier maintenance. This approach is particularly useful in large organizations with multiple frontend teams or when dealing with legacy codebases that need to be incrementally modernized.
On the other hand, microservices are employed when designing the backend architecture of an application. With microservices, the backend is split into small, autonomous services, each responsible for a specific business capability. This promotes better scalability, fault isolation, and independent deployment of services. Microservices are a better fit for applications with complex business logic, requiring flexibility in technology choices, and the ability to scale different components independently.
Below is the chart that shows the differences between microservices and micro frontends.
In summary, use micro frontends when dealing with frontend complexity and multiple development teams, and opt for microservices when you need to create a scalable and modular backend architecture. Both patterns can complement each other in building a comprehensive, decoupled, and flexible system.
Note: I have taken the help of OpenAI in some parts of this tutorial.