๐Ÿ“„API Architecture Customization

1. Introduction

As the demand for web services continues to increase, the importance of building efficient and scalable APIs has become more important than ever. Node.js has become a popular platform for building APIs due to its event-driven, non-blocking I/O model that makes it ideal for building real-time web applications.

However, as with any technology, there are always opportunities for improvement. In this document, we will explore some best practices for improving your API architecture in Node.js. We will cover some topics to improve the Guardian API.

Whether you are building a new API or looking to improve an existing one, the recommendations in this document will help the Guardian to build a more reliable, scalable, and maintainable API.

2. Web Proxy

As web applications grow in complexity, the need for a robust and scalable proxy server becomes increasingly important. While Nginx has been a popular choice for many years, Node.js Express with TypeScript has emerged as a powerful alternative due to its flexibility, scalability, and ease of customization.

In this document, we will explore the benefits of migrating a proxy application from Nginx to Node.js Express with TypeScript. We will cover topics such as performance optimization, security enhancements, and customization of headers, requests, and responses.

Whether you are looking to improve the scalability of your application or add new security layers, the migration to Node.js Express with TypeScript will provide you with the tools necessary to achieve your goals. By leveraging the power of TypeScript, you can write more maintainable code and take advantage of its type checking capabilities to catch errors early in the development process.

So, let's get started and see how we can migrate our proxy application to Node.js Express with TypeScript and unlock its full potential!

Why migrate? Here are some reasons why migrating a proxy application from Nginx to Node.js Express can be beneficial:

Flexibility: While Nginx is a powerful tool for serving static files and proxying requests, it can be limiting when it comes to customizing headers, requests, and responses. Node.js Express, on the other hand, provides a lot of flexibility when it comes to building proxy servers. It allows you to write JavaScript code to handle requests and responses, and provides a lot of middleware that can be used to add features such as authentication, caching, and compression.

Performance: While Nginx is known for its speed and efficiency, Node.js Express can be just as fast, if not faster, when properly optimized. Node.js Express uses an event-driven, non-blocking I/O model that makes it ideal for handling a large number of simultaneous connections. Additionally, because Node.js Express is written in JavaScript, it can be optimized using various tools and techniques to achieve maximum performance.

Ease of Development: Nginx configuration files can be complex and difficult to manage, especially for developers who are not familiar with the syntax. Node.js Express, on the other hand, uses JavaScript, which is a familiar language for many developers. Additionally, Node.js Express has a large community and a lot of documentation and tutorials available, making it easier for developers to get started.

Customization: Node.js Express provides a lot of customization options, allowing you to tailor your proxy server to fit your specific needs. For example, you can easily add custom middleware to handle specific types of requests or responses, or add your own error handling to handle errors in a specific way. Additionally, because Node.js Express is written in JavaScript, it can be easily extended with third-party modules from npm.

TypeScript Support: Node.js Express has built-in support for TypeScript, which is a superset of JavaScript that provides additional features such as static typing and interfaces. TypeScript can help catch errors before they occur and make code more maintainable and easier to read.

How hard would it be?

With simple steps we can transform the current web-proxy module into a NodeJS application:

import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import path from 'path';
const app = express();


const wsProxy = createProxyMiddleware('/ws/', {
 target: 'http://api-gateway:3002',
 changeOrigin: true,
 ws: true,
});


const apiProxy = createProxyMiddleware('/api/v1/', {
 target: "http://api-gateway:3002",
 changeOrigin: true,
 xfwd: true,
 onProxyReq: (proxyReq, req, res) => {
   proxyReq.setHeader("X-Forwarded-For", req.ip);
   proxyReq.setHeader("X-Real-IP", req.ip);
   proxyReq.setHeader("X-Forwarded-Proto", req.protocol);
   proxyReq.setHeader("Surrogate-Control", "no-store");
   proxyReq.setHeader(
     "Cache-Control",
     "no-store, no-cache, must-revalidate, proxy-revalidate"
   );
   proxyReq.setHeader("Pragma", "no-cache");
   proxyReq.setHeader("Expires", "0");
 },
 timeout: 1200000,
 limit: "1024mb",
 proxyTimeout: 1200000,
 followRedirects: true,
 onProxyRes: (proxyRes, req, res) => {
   res.removeHeader("Surrogate-Control");
   res.removeHeader("Cache-Control");
   res.removeHeader("Pragma");
   res.removeHeader("Expires");
 },
});


const mrvSenderProxy = createProxyMiddleware('/mrv-sender', {
 target: 'http://mrv-sender:3005/',
 changeOrigin: true,
 xfwd: true,
 onProxyReq: (proxyReq, req, res) => {
   proxyReq.setHeader('X-Forwarded-For', req.ip);
 },
 onProxyRes: (proxyRes, req, res) => {
   proxyRes.headers['X-Proxy-By'] = 'node-http-proxy';
 },
 logLevel: 'debug',
});


const topicViewerProxy = createProxyMiddleware('/topic-viewer', {
   target: 'http://topic-viewer:3006',
   changeOrigin: true,
   xfwd: true,
   onProxyReq: (proxyReq, req, res) => {
     proxyReq.setHeader('X-Forwarded-For', req.ip);
   },
   onProxyRes: (proxyRes, req, res) => {
     proxyRes.headers['X-Proxy-By'] = 'node-http-proxy';
   },
   logLevel: 'debug',
});


const apiDocsProxy = createProxyMiddleware('/api-docs/v1', {
 target: 'http://api-docs:3001',
 changeOrigin: true,
 xfwd: true,
 onProxyReq: (proxyReq, req, res) => {
   proxyReq.setHeader('X-Forwarded-For', req.ip);
 },
 onProxyRes: (proxyRes, req, res) => {
   proxyRes.headers['X-Proxy-By'] = 'node-http-proxy';
 },
 logLevel: 'debug',
});



const mongoAdminProxy = createProxyMiddleware('/mongo-admin', {
 target: 'http://mongo-express:8081',
 changeOrigin: true,
 xfwd: true,
 onProxyReq: (proxyReq, req, res) => {
   proxyReq.setHeader('X-Forwarded-For', req.ip);
 },
 onProxyRes: (proxyRes, req, res) => {
   proxyRes.headers['X-Proxy-By'] = 'node-http-proxy';
 },
 logLevel: 'debug',
});


app.use(wsProxy);
app.use(apiProxy);
app.use(mrvSenderProxy);
app.use(topicViewerProxy);
app.use(apiDocsProxy);
app.use(mongoAdminProxy);


app.use('/', express.static('public'));