Search This Blog

Showing posts with label Node. Show all posts
Showing posts with label Node. Show all posts

Wednesday, January 29, 2025

How to use PM2 to Manage Multiple Node Services in production

 If you want to manage and monitor the services, you can use PM2, a process manager for Node.js. This is particularly useful in production environments.

  1. Install PM2 globally:


    npm install pm2 -g
  2. Create an ecosystem file (e.g., ecosystem.config.js) to define all services:


    module.exports = { apps: [ { name: 'microservice1', script: './microservice1/server.js', watch: true, env: { NODE_ENV: 'production', }, }, { name: 'microservice2', script: './microservice2/server.js', watch: true, env: { NODE_ENV: 'production', }, }, { name: 'microservice3', script: './microservice3/server.js', watch: true, env: { NODE_ENV: 'production', }, }, ], };
  3. Start all services:


    pm2 start ecosystem.config.js
  4. Monitor services:

    pm2 list
Cheers,

Kapil 

How can package all node js microservices and start in one command

 

Using npm scripts to start all services

If your microservices are not containerized, you can set up an npm script to run all services with one command.

  1. Create an npm script in your root package.json that runs all microservices in parallel using something like concurrently or npm-run-all.

    First, install the necessary package:

    npm install concurrently --save-dev

  2. Add a script to your root package.json:

    json:
    { "scripts": { "start": "concurrently \"npm run start:microservice1\" \"npm run start:microservice2\" \"npm run start:microservice3\"", "start:microservice1": "cd microservice1 && npm start", "start:microservice2": "cd microservice2 && npm start", "start:microservice3": "cd microservice3 && npm start" } }
  3. Run all services with a single command:

    npm start

This will start all your microservices concurrently.


There are other ways as well. If if you have rest services in different tech like JAVA aor Python etc. we can use docker compose. 

Check docker compose on this link -> how-can-package-all-microservices-using-docker

Other option could be PM2 -> how-to-use-pm2-to-manage-multiple-node-services

Cheers:

Kapil

Wednesday, January 15, 2025

How to post request in node js using http-proxy-middleware

 

Recently we faced issue to post the request via api server to another server to fix follow the 

code as below:

In node app.js use following to proxy post request to different server:

const postProxy = createProxyMiddleware({

target: 'http://localhost:4000/', // Target server
changeOrigin: true, // Change the origin header to the target URL
pathRewrite: {
'^/api': '', // Remove /api from the path when forwarding
},
on: {
proxyReq: fixRequestBody
},
onProxyReq: (proxyReq, req, res) => {
// Forward request body for POST requests
if (req.body && Object.keys(req.body).length > 0) {
const bodyData = JSON.stringify(req.body);
proxyReq.setHeader('Content-Type', 'application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
console.log(proxyReq);
}
},
logLevel: 'debug', // Enable detailed logs
});
// Proxy POST requests to /api/*
app.use(
'/api', postProxy
);


Cheers

Happy Coding !!

Tuesday, January 14, 2025

Microservice in Node js using API hub.

 To implement an API Hub design pattern with JWT authentication in your microservices architecture, the API Hub will serve as a central gateway to route requests to different microservices (User Service, Product Service). It ensures security, scalability, and simplified client interaction.


Architecture

  1. API Hub (Node.js):

    • Acts as a central gateway.
    • Verifies JWT tokens for authentication.
    • Routes requests to the appropriate microservice.
  2. Microservices (User & Product):

    • Handle specific domains (user and product).
    • Authenticate requests via JWT verification.
  3. JWT Authentication:

    • API Hub validates JWT.
    • Microservices assume the API Hub has already authenticated requests.
  4. Angular Frontend:

    • Sends requests with JWT tokens obtained after login.

Implementation

1. Create the API Hub

Install Dependencies
mkdir api-hub cd api-hub npm init -y npm install express http-proxy-middleware jsonwebtoken body-parser cors dotenv
api-hub/index.js
require('dotenv').config(); const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const jwt = require('jsonwebtoken'); const bodyParser = require('body-parser'); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(bodyParser.json()); app.use(require('cors')()); // JWT Authentication Middleware const authenticateJWT = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ message: 'Unauthorized' }); jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.status(403).json({ message: 'Forbidden' }); req.user = user; // Attach user info to the request next(); }); }; // Route to Login (for generating JWT tokens) app.post('/login', (req, res) => { const { username, password } = req.body; // Mock authentication if (username === 'admin' && password === 'admin') { const token = jwt.sign({ username, role: 'admin' }, process.env.JWT_SECRET, { expiresIn: '1h' }); return res.json({ token }); } res.status(401).json({ message: 'Invalid credentials' }); }); // Proxy Middleware app.use( '/users', authenticateJWT, createProxyMiddleware({ target: 'http://localhost:3001', changeOrigin: true }) ); app.use( '/products', authenticateJWT, createProxyMiddleware({ target: 'http://localhost:3002', changeOrigin: true }) ); // Start Server app.listen(PORT, () => console.log(`API Hub running on http://localhost:${PORT}`));
.env
PORT=3000 JWT_SECRET=your_jwt_secret_key

2. Update User and Product Services

  • Add a middleware to verify JWT tokens.
  • JWT is validated at the API Hub, but additional verification can be done in services for security.
Example Middleware: authMiddleware.js

const jwt = require('jsonwebtoken'); module.exports = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ message: 'Unauthorized' }); jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.status(403).json({ message: 'Forbidden' }); req.user = user; next(); }); };

Add this middleware to all secure routes in both services:


const authMiddleware = require('./authMiddleware'); app.use(authMiddleware); // Apply globally

3. Angular Frontend Integration

Install Dependencies

npm install @auth0/angular-jwt
app.module.ts

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { JwtModule } from '@auth0/angular-jwt'; import { AppComponent } from './app.component'; export function tokenGetter() { return localStorage.getItem('access_token'); } @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, HttpClientModule, JwtModule.forRoot({ config: { tokenGetter, allowedDomains: ['localhost:3000'], // API Hub disallowedRoutes: ['http://localhost:3000/login'], }, }), ], bootstrap: [AppComponent], }) export class AppModule {}
user.service.ts (with JWT Authentication)

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class UserService { private baseUrl = 'http://localhost:3000/users'; constructor(private http: HttpClient) {} getUsers(): Observable<any> { return this.http.get(this.baseUrl); } login(credentials: any): Observable<any> { return this.http.post('http://localhost:3000/login', credentials); } }
app.component.ts

import { Component } from '@angular/core'; import { UserService } from './services/user.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { users: any[] = []; token: string | null = null; constructor(private userService: UserService) {} login() { this.userService.login({ username: 'admin', password: 'admin' }).subscribe( (response) => { this.token = response.token; localStorage.setItem('access_token', this.token); this.loadUsers(); }, (error) => console.error('Login failed', error) ); } loadUsers() { this.userService.getUsers().subscribe((data) => (this.users = data)); } }
app.component.html

<div> <button (click)="login()">Login</button> <ul> <li *ngFor="let user of users">{{ user.name }}</li> </ul> </div>

Key Features of the Setup

  1. API Hub:
    • Centralized authentication.
    • Routes requests to microservices securely.
  2. JWT Authentication:
    • Secure API communication.
    • Tokens managed by the frontend and verified at the backend.
  3. Scalable Design:
    • User and Product services are independently deployable.
    • API Hub is extendable to include more microservices.

This design ensures a robust, secure, and modular architecture suitable for modern microservices-based applications.


Cheers !! 

Thursday, January 9, 2025

How to handle cors error in node js


     CORS (Cross-Origin Resource Sharing) errors occur when a browser blocks a request made to a server that is on a different origin (domain, protocol, or port) than the client making the request. 

    To handle CORS errors in a Node.js application, you need to configure the server to explicitly allow cross-origin requests.

Following are Steps to Handle CORS in Node.js:


1. Use the cors Package

The easiest way to handle CORS in Node.js is by using the popular cors middleware package.

Install the cors Package:
bash

npm install cors
Example Usage in Your App:
const express = require('express'); const cors = require('cors'); const app = express(); // Allow CORS for all origins app.use(cors()); // Optional: Allow specific origins or methods const corsOptions = { origin: 'http://example.com', // Replace with your frontend's origin methods: ['GET', 'POST', 'PUT', 'DELETE'], // Allowed HTTP methods allowedHeaders: ['Content-Type', 'Authorization'], // Allowed headers }; app.use(cors(corsOptions)); app.get('/api/data', (req, res) => { res.json({ message: 'CORS is working!' }); }); app.listen(3000, () => { console.log('Server running on port 3000'); });

2. Manually Set CORS Headers

If you don't want to use the cors package, you can manually set CORS headers in your responses.

Example:
const express = require('express'); const app = express(); app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); // Allow all origins res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // Handle preflight requests (OPTIONS method) if (req.method === 'OPTIONS') { return res.status(204).end(); } next(); }); app.get('/api/data', (req, res) => { res.json({ message: 'CORS headers set manually!' }); }); app.listen(3000, () => { console.log('Server running on port 3000'); });

3. Debugging CORS Issues

If you are still encountering CORS issues:

  • Check the Origin Header: Ensure that the client's request includes the correct Origin header.
  • Check Preflight Requests: For PUT, DELETE, and other methods, browsers send a preflight OPTIONS request to check permissions. Ensure your server handles this method.
  • Check Browser Console: The error messages in the console often provide hints about what is misconfigured.
  • Check API Proxy Settings: If you're using a proxy (e.g., in Angular, React, or Vue), ensure the proxy is properly routing requests.

4. For Development Environments

If you're testing locally and don't want to configure strict CORS rules, you can allow all origins temporarily:

app.use(cors({ origin: '*' }));

5. For Production

For production environments, always restrict access to trusted origins:


const corsOptions = { origin: ['https://trusted-frontend.com', 'https://another-trusted-site.com'], // List of trusted origins methods: ['GET', 'POST'], allowedHeaders: ['Content-Type', 'Authorization'], }; app.use(cors(corsOptions));

This approach ensures that your API complies with security requirements while avoiding CORS errors in browsers.

Friday, January 3, 2025

How to Prevent the "Cannot Read Property 'map' of Undefined" Error

  

    One of the most common errors encountered by JavaScript developers, especially when working with arrays and React, is the infamous:

TypeError: Cannot read property 'map' of undefined

This error indicates that the code is trying to call the map method on a value that is undefined. Here, we’ll break down the causes of this error and provide actionable solutions to prevent it.


Understanding the Problem

The map method is used to iterate over an array and transform its elements. If the value you’re trying to call map on isn’t an array (e.g., undefined, null, or another non-array type), JavaScript will throw this error.

Common Scenarios

  1. Undefined or null data:

    const items = undefined;
    items.map(item => console.log(item)); // TypeError
  2. Asynchronous data loading: When fetching data from an API, the array might not be available immediately.

    const [data, setData] = useState();
    useEffect(() => {
        fetch('/api/data')
            .then(response => response.json())
            .then(fetchedData => setData(fetchedData));
    }, []);
    
    data.map(item => console.log(item)); // TypeError
  3. Incorrect initial value: You might set the state to undefined or forget to initialize it as an empty array.


Strategies to Prevent the Error

1. Initialize Variables Properly

Always initialize variables that will hold arrays with an empty array. This ensures the map method can be safely called.

const items = [];
items.map(item => console.log(item)); // Safe, no error

2. Use Optional Chaining

Optional chaining (?.) prevents accessing properties or methods on undefined or null.

items?.map(item => console.log(item)); // No error, but does nothing if items is undefined

3. Provide Default Values

Using default parameters or the || operator ensures a fallback array if the value is undefined.

Example 1: Default Parameter

function processItems(items = []) {
    items.map(item => console.log(item));
}

Example 2: Logical OR

(items || []).map(item => console.log(item));

4. Check the Type Before Calling map

Explicitly validate the type of the variable to ensure it is an array.

if (Array.isArray(items)) {
    items.map(item => console.log(item));
} else {
    console.log('items is not an array');
}

5. Handle Asynchronous Data Gracefully

When working with APIs or asynchronous operations, make sure to handle the loading state properly.

const [data, setData] = useState([]); // Initialize with an empty array

useEffect(() => {
    fetch('/api/data')
        .then(response => response.json())
        .then(fetchedData => setData(fetchedData))
        .catch(error => console.error('Error fetching data:', error));
}, []);

return (
    <div>
        {data.map(item => (
            <p key={item.id}>{item.name}</p>
        ))}
    </div>
);

Debugging Tips

If you encounter this error, follow these steps to debug it:

  1. Log the Variable: Use console.log to check the value of the variable before calling map.

    console.log(items);
  2. Check Data Flow: Trace the origin of the variable to ensure it’s being set correctly.

  3. Handle Edge Cases: Consider scenarios where the variable might be undefined or null, especially when working with dynamic or external data.


Happy Coding 

Cheers,
Kapil

Tuesday, December 31, 2024

How to update node application without server restart


Updating Node.js Applications Without Manual Restart Using Nodemon

When developing Node.js applications, manually restarting the server every time you make changes to your code can be both time-consuming and tedious. Thankfully, tools like Nodemon simplify the development workflow by automatically restarting your Node.js application whenever a file changes. This article explores how to set up and use Nodemon to enhance your productivity.

What is Nodemon?

Nodemon is a utility that monitors changes in your Node.js application files and automatically restarts the server when a change is detected. It’s particularly useful for developers who need rapid feedback while coding.

Key Features of Nodemon

  • Automatic server restarts on file changes.

  • Supports custom configurations for monitoring specific files or directories.

  • Compatible with most Node.js frameworks and libraries.

  • Lightweight and easy to set up.

Installing Nodemon

To get started with Nodemon, you’ll need to have Node.js and npm (Node Package Manager) installed on your system.

  1. Open your terminal.

  2. Install Nodemon globally by running:

    npm install -g nodemon

Alternatively, you can add it as a development dependency to your project:

    npm install --save-dev nodemon

Running Your Application with Nodemon

Using Nodemon to run your application is simple. Instead of starting your app with node, use nodemon:

nodemon app.js

and if nodemon is not installed globally then execute following:

./node_modules/.bin/nodemon app.js

Here, app.js is the entry point of your application. Nodemon will now monitor your project files and automatically restart the server when any changes are detected.

Customizing Nodemon

Using a Configuration File

Nodemon allows you to create a configuration file for more advanced setups. By default, it looks for a nodemon.json file in the root of your project. Here’s an example configuration:

{
  "watch": ["src"],
  "ext": "js,json,html",
  "ignore": ["node_modules"],
  "exec": "node src/index.js"
}
  • watch: Specifies the directories or files to monitor.

  • ext: Defines the file extensions to watch.

  • ignore: Excludes specific files or directories from monitoring.

  • exec: Specifies the command to run your application.

Command-Line Options

Nodemon also supports various command-line options for customization:

  • Watch Specific Files/Directories:

    nodemon --watch src
  • Ignore Files/Directories:

    nodemon --ignore logs
  • Specify Extensions to Watch:

    nodemon --ext js,html

Enhancing Productivity with Nodemon

Here are a few tips to make the most of Nodemon:

  1. Combine with Environment Variables: Use environment variables to manage different configurations:

    nodemon -e js --exec "NODE_ENV=development node app.js"
  2. Integrate with npm Scripts: Define a script in your package.json for easy use:

    "scripts": {
      "start:dev": "nodemon app.js"
    }

    Then run:

    npm run start:dev
  3. Use Debugging Tools: Nodemon works seamlessly with Node.js debugging tools. Start your app in debug mode:

    nodemon --inspect app.js

Conclusion

Nodemon is a powerful tool that eliminates the hassle of manually restarting your Node.js server during development. With its flexibility and ease of use, it’s a must-have for any Node.js developer looking to streamline their workflow.

Set up Nodemon today and enjoy a smoother, more efficient development experience!

Cheers,

Kapil 

Thursday, December 26, 2024

Error: Can only be default-imported using the 'esModuleInterop' flag

 

Recently we have faced issue with node js app with following error:


node_modules/@types/express/index"' can only be default-imported using
the 'esModuleInterop' flag

Error Line: import express from "express";

Reason we see esModuleInterop flag was not set as true and ES versions were
not compatible.

To fix this error, we have set

"esModuleInterop" : true

in tsconfig.json in the Compiler-options

Then issue was sorted.

Cheers,
Kapil

Monday, August 31, 2020

Solved : VSCode: Debugging Error “Breakpoint set but not yet bound" - Angular, Node

 Hi, 

I was facing issue while setting up debugger with chrome with Angular app. My Chrome Launch configuration was : 


    "configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}"
}


After investigation found that it was not able to figure out webRoot correctly since my app was one more level down into app folder hence i have changed webRoot Path as below which did trick for me :) 


    "configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"url": "http://localhost:4200",
"webRoot": "${workspaceFolder}/myAppStore/"
}

Relaunched the debug and it worked.

Cheers,

Kapil 


Popular Posts