Day 3: HTTP Module and Building a Basic Server In Node.JS

Day 3: HTTP Module and Building a Basic Server In Node.JS

1. Theory:


Introduction to Networking in Node.js

  • What is Networking?

    • Networking refers to the communication between a client and a server using network protocols like HTTP, TCP, UDP, etc.
  • What is HTTP?

    • HTTP (HyperText Transfer Protocol) is a protocol used for transferring data over the web. In Node.js, the http module allows you to create an HTTP server to listen for incoming requests and send responses to clients.

Understanding HTTP Protocols

  • Request and Response Cycle:

    • The client (browser, Postman, etc.) sends an HTTP request to the server.

    • The server processes the request and sends back an HTTP response.

  • HTTP Methods:

    • GET: Used to retrieve data from the server.

    • POST: Used to send data to the server.

    • PUT, DELETE: Other methods used for modifying or deleting data.


Basics of Creating an HTTP Server in Node.js

  • Using the http Module:

    • The http module in Node.js allows you to create a simple web server that can handle incoming HTTP requests and send responses.

    • You can handle different routes (e.g., /home, /about) and different HTTP methods (e.g., GET, POST) to serve different types of content.


TCP (Transmission Control Protocol):

  • Strengths:

    • Reliable: TCP ensures that all data is delivered in the correct order, with error checking and retransmission of lost packets.

    • Connection-Oriented: A reliable connection is established between the two endpoints before data transfer begins, ensuring consistency.

    • Use Case in Real-Time Communication:

      • Chat applications: Many real-time messaging apps, such as WhatsApp or Facebook Messenger, use TCP because reliability is crucial in text-based communication. Missing or out-of-order messages would disrupt the user experience.

      • VoIP with fallback to TCP: In cases where network conditions are unreliable, some VoIP systems fall back to TCP for improved reliability.

      • Video conferencing (with TCP fallback): Some systems use TCP to ensure delivery, but usually at the cost of higher latency.

    const net = require("net");
    const readline = require("readline");

    // Create a TCP server
    const server = net.createServer((socket) => {
      console.log("Client connected");
      socket.write("Hello, TCP World!\n");

      // Receive data from the client
      socket.on("data", (data) => {
        console.log(`Client says: ${data}`);
        socket.write(`You said: ${data}`); // Echo the message back
      });

      // Close the connection
      socket.on("end", () => {
        console.log("Client disconnected");
      });

      // Now allow input from the server terminal and send to client
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });

      rl.on("line", (input) => {
        socket.write(`Server says: ${input}\n`);
      });
    });

    // Listen on port 4000
    server.listen(4000, () => {
      console.log("TCP server listening on port 4000");
    });

UDP (User Datagram Protocol):

  • Strengths:

    • Fast and Low Latency: UDP is faster than TCP because it doesn’t establish a connection or handle packet retransmission, which makes it ideal for real-time communication where speed is more important than reliability.

    • Connectionless: UDP sends packets without establishing a connection, so it is lightweight and better for real-time, high-speed transmissions.

  • Use Case in Real-Time Communication:

    • Voice over IP (VoIP): Applications like Zoom, Skype, or Google Meet often use UDP for transmitting voice data, as low latency is critical, and occasional packet loss is acceptable.

    • Online Gaming: Many real-time multiplayer games use UDP for transmitting game data, where speed and low latency are prioritized over perfect delivery. Lost packets are usually acceptable because real-time updates happen continuously.

    • Live Streaming: UDP is used for real-time video and audio streaming because it can handle large amounts of data without waiting for acknowledgment of each packet, reducing latency.

2. Practical:


Task 1: Create a Basic HTTP Server

What to do:

  • Create a simple Node.js HTTP server using the http module that listens on port 3000 and responds with a message.

Example:

const http = require('http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  // Set the response header
  res.writeHead(200, { 'Content-Type': 'text/plain' });

  // Send a simple response
  res.end('Hello, World!\n');
});

// The server listens on port 3000
server.listen(3000, () => {
  console.log('Server is listening on port 3000...');
});

Run the server:

node server.js

Task 2: Responding with Static Content (HTML and JSON)

What to do:

  • Modify the server to respond with HTML content when the request URL is /home and with JSON data when the request URL is /api.

Example:

const http = require('http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  if (req.url === '/home') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Welcome to the Home Page!</h1>');
  } else if (req.url === '/api') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    const data = {
      message: 'Hello, this is JSON data!',
      status: 'success',
    };
    res.end(JSON.stringify(data));
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('404 - Not Found');
  }
});

// The server listens on port 3000
server.listen(3000, () => {
  console.log('Server is listening on port 3000...');
});

Test the server:


Task 3: Handling Different Routes and HTTP Methods (GET, POST)

What to do:

  • Modify the server to handle two different routes:

    • /about: Responds with a simple HTML message using the GET method.

    • /submit: Accepts POST requests and responds with the data that the client submits.

Example:

const http = require('http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  if (req.method === 'GET' && req.url === '/about') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>About Us</h1><p>This is the about page.</p>');
  } else if (req.method === 'POST' && req.url === '/submit') {
    let body = '';

    // Collect the data sent by the client
    req.on('data', chunk => {
      body += chunk.toString();
    });

    // Once all data is received, respond with it
    req.on('end', () => {
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end(`Received data: ${body}`);
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('404 - Not Found');
  }
});

// The server listens on port 3000
server.listen(3000, () => {
  console.log('Server is listening on port 3000...');
});

Test the server:

Example using curl:

curl -X POST -d "name=John&age=25" http://localhost:3000/submit

Output:

Received data: name=John&age=25

3. Extended Practical Examples:

Task 4: Serve a Static HTML File

What to do:

  • Create an HTML file (e.g., index.html) and serve it using the fs module with the HTTP server.

Example:

  1. Create an index.html file:

     <!DOCTYPE html>
     <html lang="en">
       <head>
         <meta charset="UTF-8" />
         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
         <title>Portfolio</title>
         <style>
           * {
             margin: 0;
             padding: 0;
             box-sizing: border-box;
           }
           body {
             font-family: Arial, sans-serif;
             line-height: 1.6;
             background-color: #f4f4f4;
             color: #333;
           }
           header {
             background-color: #333;
             color: #fff;
             padding: 1rem 0;
             text-align: center;
           }
           header h1 {
             margin-bottom: 0.5rem;
           }
           header p {
             font-size: 1.1rem;
           }
           nav {
             background-color: #444;
             padding: 1rem;
             text-align: center;
           }
           nav a {
             color: #fff;
             margin: 0 15px;
             text-decoration: none;
             font-weight: bold;
           }
           nav a:hover {
             text-decoration: underline;
           }
           .container {
             max-width: 1100px;
             margin: 2rem auto;
             padding: 0 2rem;
           }
           .about,
           .projects {
             background-color: #fff;
             padding: 2rem;
             margin-bottom: 1.5rem;
             border-radius: 5px;
             box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
           }
           .about h2,
           .projects h2 {
             margin-bottom: 1rem;
           }
           .about p {
             font-size: 1.1rem;
             line-height: 1.8;
           }
           .projects {
             display: grid;
             grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
             gap: 1.5rem;
           }
           .project-card {
             background-color: #f9f9f9;
             padding: 1.5rem;
             border-radius: 5px;
             box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
           }
           .project-card h3 {
             margin-bottom: 0.5rem;
           }
           .project-card p {
             margin-bottom: 1rem;
           }
           footer {
             background-color: #333;
             color: #fff;
             text-align: center;
             padding: 1rem 0;
           }
           footer p {
             margin: 0;
           }
         </style>
       </head>
       <body>
         <header>
           <h1>Sungava College</h1>
           <p>Web Developer | Designer | Programmer</p>
         </header>
    
         <nav>
           <a href="#about">About</a>
           <a href="#projects">Projects</a>
           <a href="#contact">Contact</a>
         </nav>
    
         <div class="container">
           <section id="about" class="about">
             <h2>About Me</h2>
             <p>
               Hello! I'm Apple, a passionate web developer with experience in
               building dynamic and responsive websites. I enjoy turning complex
               problems into simple, beautiful, and intuitive solutions.
             </p>
           </section>
    
           <section id="projects" class="projects">
             <h2>Projects</h2>
             <div class="project-card">
               <h3>Project One</h3>
               <p>A responsive website built with HTML, CSS, and JavaScript.</p>
               <a href="#">View Project</a>
             </div>
             <div class="project-card">
               <h3>Project Two</h3>
               <p>A dynamic web application using the MERN stack.</p>
               <a href="#">View Project</a>
             </div>
             <div class="project-card">
               <h3>Project Three</h3>
               <p>An eCommerce platform built using React and Node.js.</p>
               <a href="#">View Project</a>
             </div>
           </section>
         </div>
    
         <footer>
           <p>&copy; 2024 Sungava College. All Rights Reserved.</p>
         </footer>
       </body>
     </html>
    
  2. Modify the server to read and serve this file:

     const http = require('http');
     const fs = require('fs');
    
     // Create an HTTP server
     const server = http.createServer((req, res) => {
       if (req.url === '/home') {
         fs.readFile('index.html', (err, data) => {
           if (err) {
             res.writeHead(500, { 'Content-Type': 'text/plain' });
             res.end('500 - Internal Server Error');
           } else {
             res.writeHead(200, { 'Content-Type': 'text/html' });
             res.end(data);
           }
         });
       } else {
         res.writeHead(404, { 'Content-Type': 'text/plain' });
         res.end('404 - Not Found');
       }
     });
    
     // The server listens on port 3000
     server.listen(3000, () => {
       console.log('Server is listening on port 3000...');
     });
    

Test the server:


Task 5: Handle Query Parameters

What to do:

  • Handle query parameters from a URL and return dynamic content based on those parameters.

Example:

const http = require("http");
const url = require("url");

// Create an HTTP server
const server = http.createServer((req, res) => {
  // Parse the URL and extract query parameters
  const parsedUrl = url.parse(req.url, true);
  const queryObject = parsedUrl.query;

  // Check if the path starts with /greet/
  if (req.url.startsWith("/greet/")) {
    // Extract the "name" query parameter, or default to "Guest"
    const name = queryObject.name || "Guest";

    // Set response header and send the greeting message
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end(`Hello, ${name}!`);
  } else {
    // Handle 404 Not Found if the route doesn't match /greet/
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.end("404 - Not Found");
  }
});

// The server listens on port 3000
server.listen(3000, () => {
  console.log("Server is listening on port 3000...");
});

Test the server: