node-jsNode.js Syntax

Node.js

Installation

  1. Download and Install: Visit the official Node.js website and download the installer for your operating system.
  2. Verify Installation:
    node -v
    npm -v

Modules

Modules are reusable blocks of code in Node.js. They help in organizing code into manageable pieces.

CommonJS Modules

Node.js uses the CommonJS module system.

  • Exporting Modules:

    // math.js
    function add(a, b) {
      return a + b;
    }
     
    module.exports = { add };
  • Importing Modules:

    // app.js
    const math = require('./math');
     
    console.log(math.add(2, 3)); // Output: 5

ES Modules

As of Node.js v12+, ES Modules are supported using the .mjs extension or by setting "type": "module" in package.json.

  • Exporting Modules:

    // math.mjs
    export function add(a, b) {
      return a + b;
    }
  • Importing Modules:

    // app.mjs
    import { add } from './math.mjs';
     
    console.log(add(2, 3)); // Output: 5

Built-in Modules

Node.js comes with several built-in modules to perform various tasks.

File System (fs)

Handles file operations.

  • Reading a File:

    const fs = require('fs');
     
    fs.readFile('example.txt', 'utf8', (err, data) => {
      if (err) throw err;
      console.log(data);
    });
  • Writing to a File:

    fs.writeFile('example.txt', 'Hello, World!', (err) => {
      if (err) throw err;
      console.log('File written successfully');
    });

Path (path)

Utilities for handling and transforming file paths.

  • Joining Paths:

    const path = require('path');
     
    const fullPath = path.join(__dirname, 'folder', 'file.txt');
    console.log(fullPath);
  • Resolving Paths:

    const resolvedPath = path.resolve('folder/file.txt');
    console.log(resolvedPath);

HTTP (http)

Creates HTTP servers and handles HTTP requests.

  • Creating a Server:
    const http = require('http');
     
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello, World!\n');
    });
     
    server.listen(3000, () => {
      console.log('Server running at http://localhost:3000/');
    });

Asynchronous Programming

Node.js is inherently asynchronous, allowing non-blocking operations.

Callbacks

Functions passed as arguments to handle asynchronous operations.

const fs = require('fs');
 
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});

Promises

Promises represent the eventual completion (or failure) of an asynchronous operation.

  • Using Promises:
    const fs = require('fs').promises;
     
    fs.readFile('example.txt', 'utf8')
      .then(data => console.log(data))
      .catch(err => console.error(err));

Async/Await

Syntactic sugar over Promises for cleaner asynchronous code.

const fs = require('fs').promises;
 
async function readFile() {
  try {
    const data = await fs.readFile('example.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}
 
readFile();

Creating a Basic Server

Using the http module to create a simple server.

const http = require('http');
 
const server = http.createServer((req, res) => {
  // Set response header
  res.writeHead(200, { 'Content-Type': 'text/plain' });
 
  // Send response body
  res.end('Hello, Node.js!\n');
});
 
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Package Management with npm

npm (Node Package Manager) is used to manage project dependencies.

Initializing a Project

Create a package.json file.

npm init

Follow the prompts or use -y to accept defaults.

npm init -y

Installing Packages

  • Local Installation:

    npm install express
  • Global Installation:

    npm install -g nodemon
  • Saving as a Dependency:

    npm install lodash --save
  • Saving as a Dev Dependency:

    npm install jest --save-dev

package.json

Defines project metadata and dependencies.

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "A sample Node.js application",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.20",
    "jest": "^29.0.0"
  },
  "author": "Your Name",
  "license": "ISC"
}

Express.js

Introduction

Express.js is a minimal and flexible Node.js web application framework that provides robust features for building single and multi-page, and hybrid web applications.

Installation

Install Express locally within your project.

npm install express

Creating an Express App

// app.js
const express = require('express');
const app = express();
const PORT = 3000;
 
// Define a route
app.get('/', (req, res) => {
  res.send('Hello, Express!');
});
 
// Start the server
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Middleware

Middleware functions are functions that have access to the request (req) and response (res) objects, and the next function in the request-response cycle.

Built-in Middleware

  • express.json(): Parses incoming JSON requests.

    app.use(express.json());
  • express.urlencoded(): Parses incoming requests with URL-encoded payloads.

    app.use(express.urlencoded({ extended: true }));

Third-party Middleware

  • morgan: HTTP request logger middleware.

    npm install morgan
    const morgan = require('morgan');
    app.use(morgan('dev'));
  • cors: Enables Cross-Origin Resource Sharing.

    npm install cors
    const cors = require('cors');
    app.use(cors());

Custom Middleware

// Custom logging middleware
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

Routing

Routing defines how an application responds to client requests for specific endpoints.

Basic Routing

app.get('/about', (req, res) => {
  res.send('About Page');
});
 
app.post('/submit', (req, res) => {
  res.send('Form Submitted');
});

Route Parameters

Parameters captured in the URL.

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`User ID: ${userId}`);
});

Query Parameters

Parameters sent in the query string.

app.get('/search', (req, res) => {
  const query = req.query.q;
  res.send(`Search Query: ${query}`);
});

Handling Requests and Responses

Request (req) Object

Contains information about the HTTP request.

  • Accessing Body:

    app.post('/data', (req, res) => {
      const data = req.body;
      res.json(data);
    });
  • Accessing Headers:

    app.get('/headers', (req, res) => {
      const userAgent = req.headers['user-agent'];
      res.send(`User-Agent: ${userAgent}`);
    });

Response (res) Object

Methods to send responses to the client.

  • res.send(): Sends a response of various types.

    res.send('Hello World');
  • res.json(): Sends a JSON response.

    res.json({ message: 'Hello, JSON' });
  • res.status(): Sets the HTTP status for the response.

    res.status(404).send('Not Found');
  • res.redirect(): Redirects to a different URL.

    res.redirect('/login');

Error Handling

Proper error handling is crucial for building robust applications.

Error-handling Middleware

Error-handling middleware has four arguments: err, req, res, and next.

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Serving Static Files

Serve static assets like HTML, CSS, JavaScript, and images.

app.use(express.static('public'));
 
// Now, files in the 'public' directory can be accessed directly.
// e.g., http://localhost:3000/images/logo.png

Using Routers

Organize routes using express.Router.

// routes/users.js
const express = require('express');
const router = express.Router();
 
// Define routes
router.get('/', (req, res) => {
  res.send('User List');
});
 
router.get('/:id', (req, res) => {
  res.send(`User ID: ${req.params.id}`);
});
 
module.exports = router;
// app.js
const express = require('express');
const app = express();
const userRoutes = require('./routes/users');
 
app.use('/users', userRoutes);
 
app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Template Engines

Render dynamic HTML pages.

Using Pug

  • Installation:

    npm install pug
  • Setup:

    app.set('view engine', 'pug');
    app.set('views', './views');
  • Creating a View:

    // views/index.pug
    html
      head
        title= title
      body
        h1 Hello, #{name}!
  • Rendering the View:

    app.get('/', (req, res) => {
      res.render('index', { title: 'Home', name: 'John' });
    });

Using EJS

  • Installation:

    npm install ejs
  • Setup:

    app.set('view engine', 'ejs');
    app.set('views', './views');
  • Creating a View:

    <!-- views/index.ejs -->
    <!DOCTYPE html>
    <html>
      <head>
        <title><%= title %></title>
      </head>
      <body>
        <h1>Hello, <%= name %>!</h1>
      </body>
    </html>
  • Rendering the View:

    app.get('/', (req, res) => {
      res.render('index', { title: 'Home', name: 'Jane' });
    });

Environment Variables

Use environment variables to manage configuration.

  • Installation:

    npm install dotenv
  • Setup:

    require('dotenv').config();
     
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`);
    });
  • .env File:

    PORT=4000
    DB_URI=mongodb://localhost:27017/mydb

Integration with Databases

Connect your Express app to a database for data persistence.

Using Mongoose with MongoDB

  • Installation:

    npm install mongoose
  • Setup and Connection:

    const mongoose = require('mongoose');
     
    mongoose.connect(process.env.DB_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    })
    .then(() => console.log('MongoDB connected'))
    .catch(err => console.error(err));
  • Defining a Schema and Model:

    const userSchema = new mongoose.Schema({
      name: String,
      email: String,
      password: String,
    });
     
    const User = mongoose.model('User', userSchema);
  • CRUD Operations:

    // Create a new user
    app.post('/users', async (req, res, next) => {
      try {
        const user = new User(req.body);
        await user.save();
        res.status(201).json(user);
      } catch (err) {
        next(err);
      }
    });
     
    // Read all users
    app.get('/users', async (req, res, next) => {
      try {
        const users = await User.find();
        res.json(users);
      } catch (err) {
        next(err);
      }
    });

Additional Topics

Security

Enhance the security of your Express applications.

  • Helmet: Helps secure Express apps by setting various HTTP headers.

    npm install helmet
    const helmet = require('helmet');
    app.use(helmet());
  • Rate Limiting: Prevents brute-force attacks.

    npm install express-rate-limit
    const rateLimit = require('express-rate-limit');
     
    const limiter = rateLimit({
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100, // limit each IP to 100 requests per windowMs
    });
     
    app.use(limiter);

Logging

Implement logging to monitor application behavior.

  • Morgan: HTTP request logger.

    const morgan = require('morgan');
    app.use(morgan('combined'));
  • Winston: General-purpose logging.

    npm install winston
    const winston = require('winston');
     
    const logger = winston.createLogger({
      level: 'info',
      format: winston.format.json(),
      transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' }),
      ],
    });
     
    // In development, log to console as well
    if (process.env.NODE_ENV !== 'production') {
      logger.add(new winston.transports.Console({
        format: winston.format.simple(),
      }));
    }
     
    app.use((req, res, next) => {
      logger.info(`${req.method} ${req.url}`);
      next();
    });

Testing

Ensure your application works as expected through testing.

  • Jest: JavaScript testing framework.

    npm install --save-dev jest
    • Example Test:

      // sum.js
      function sum(a, b) {
        return a + b;
      }
      module.exports = sum;
      // sum.test.js
      const sum = require('./sum');
       
      test('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
      });
    • Run Tests:

      npm test
  • Supertest: HTTP assertions for testing Express routes.

    npm install --save-dev supertest
    // app.test.js
    const request = require('supertest');
    const app = require('./app'); // Your Express app
     
    describe('GET /', () => {
      it('responds with Hello, Express!', (done) => {
        request(app)
          .get('/')
          .expect(200)
          .expect('Hello, Express!', done);
      });
    });