Proxy Server Pattern is one of the Design Patterns in Microservices Architecture Where one server acts as a dedicated proxy server for the outside world to all microservices.
Architecture Design
In This pattern, All Services (A, B, C, and D) can be secured behind a firewall and accessed only by Our Proxy Server. Frontend only needs to call a single service (Proxy Server) for all requests and Proxy Server takes care of calling the correct service for frontend. to All Microservices can still communicate through Synchronized and Asynchronized Messaging Tools if needed.
Implementation in Node.js
We can use any HTTP client library also for implementing our proxy server. Here we are going to use the http-proxy npm package for implementing our proxy server because of its inbuilt capability for handling proxies request.
import httpProxy from "http-proxy";
const proxyServer = httpProxy.createProxyServer();
proxyServer.on("proxyReq", (proxyReq,req,res,options) => {
const body = req.body;
if (!body) return ;
const contentType = proxyReq.getHeader("Content-Type");
if (contentType){
const bodyData = JSON.stringify(body)
proxyReq.setHeader("Content-Length", Buffer.byteLength(bodyData);
proxyReq.write(bodyData);
}
})
const handleRequest = ({ target }) => (req, res) => {
proxyServer.web(req, res, { target }, (error) => {
return res.status(503).send({ message : error.message });
});
}
export default handleRequest;
Here Our handleRequest function returns the middleware function which we can use as a Request handler for incoming HTTP requests but before that let's create our index.js file for separating individual microservices API with some prefix in API.
import express from "express";
import serviceARoutes from "serviceARoutes.js";
import serviceBRoutes from "serviceBRoutes.js";
import serviceCRoutes from "serviceCRoutes.js";
import serviceDRoutes from "serviceDRoutes.js";
const app = express();
app.use("/serviceA", serviceARoutes);
app.use("/serviceB", serviceBRoutes);
app.use("/serviceC", serviceCRoutes);
app.use("/serviceD", serviceDRoutes);
app.listen(3000)
Now suppose our microservices are deployed in some cloud provider with the following address.
Proxy Server -> proxy-service.com
Service A -> serviceA.com
Service B -> serviceB.com
Service C -> serviceC.com
Service D -> serviceD.com
Now let's create a route file for Service A, Similar file can be created also for other services with API which you want to expose, and make sure these API is available in the respective microservice.
Now our handler just transfers the request to provided target option and returns the same response to the Frontend it receives from that target microservice.
import express from "express";
const router = express.Router();
router.get("/someApi", handleRequest(
{ target : 'https://serviceA.com'}
));
router.post("/someOtherApi", handleRequest(
{ target : 'https://serviceA.com'}
));
export default router;
So Now Frontend can access Api from all services using only the proxy server instead of calling individuals service as shown below
https://proxy-service.com/serviceA/<api> instead of https://serviceA.com/<api>
https://proxy-service.com/serviceB/<api> instead of https://serviceB.com/<api>
Hope this helps! Let me know if you have any other questions.