Node.js HTTP module

Node.js is a powerful platform for building server-side applications using JavaScript. One of its core modules is the http module, which provides the capability to create HTTP servers and clients. This chapter will explore the http module in depth, covering everything from basic server creation to advanced techniques. By the end of this chapter, you will have a comprehensive understanding of how to work with the HTTP module in Node.js.

Introduction to the http Module

The http module in Node.js allows you to create web servers and handle HTTP requests and responses. It is a core module, meaning it comes bundled with Node.js and does not require any additional installation.

To use the http module, you need to require it in your Node.js script:

				
					const http = require('http');

				
			

Creating a Basic HTTP Server

Handling Requests and Responses

Creating an HTTP server in Node.js is straightforward. You use the http.createServer method, which takes a callback function that handles incoming requests and sends responses.

				
					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, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • http.createServer(callback) creates a new HTTP server.
  • The callback function takes two arguments: req (request) and res (response).
  • res.statusCode = 200 sets the HTTP status code to 200 (OK).
  • res.setHeader('Content-Type', 'text/plain') sets the Content-Type header to ‘text/plain’.
  • res.end('Hello, World!\n') sends the response body and signals that the response is complete.
  • server.listen(port, hostname, callback) makes the server listen on the specified port and hostname.
				
					// Output //
Server running at http://127.0.0.1:3000/
				
			

Listening on a Port

The server.listen method makes the server start listening for incoming connections on the specified port and hostname.

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

				
			

Explanation:

  • server.listen(3000, callback) makes the server listen on port 3000.
  • The callback function is executed once the server starts listening.
				
					// Output //
Server is listening on port 3000

				
			

Routing in Node.js

Handling Different Routes

Routing allows you to define different endpoints and handle requests differently based on the URL path.

				
					const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Home Page\n');
  } else if (req.url === '/about') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('About Page\n');
  } else {
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Page Not Found\n');
  }
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • The server checks the value of req.url to determine the requested URL path.
  • If the URL is /, it responds with ‘Home Page’.
  • If the URL is /about, it responds with ‘About Page’.
  • For any other URL, it responds with ‘Page Not Found’ and sets the status code to 404.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Query Parameters

Query parameters are used to pass additional data in the URL. You can parse them using the url module.

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

const server = http.createServer((req, res) => {
  const queryObject = url.parse(req.url, true).query;
  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(queryObject));
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • url.parse(req.url, true) parses the URL and returns an object. The second argument true makes it parse the query string into an object.
  • queryObject contains the parsed query parameters.
  • The response is set to return the JSON representation of queryObject.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

URL Parameters

URL parameters can be extracted from the URL path.

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

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url, true);
  const path = parsedUrl.pathname;
  const trimmedPath = path.replace(/^\/+|\/+$/g, '');

  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end(`You requested: ${trimmedPath}\n`);
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • url.parse(req.url, true) parses the URL and returns an object.
  • parsedUrl.pathname contains the path part of the URL.
  • trimmedPath removes leading and trailing slashes from the path.
  • The response is set to return the trimmed path.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Serving Static Files

Serving static files, such as HTML, CSS, and JavaScript files, can be done using the fs module to read and send files.

				
					const http = require('http');
const fs = require('fs');
const path = require('path');

const server = http.createServer((req, res) => {
  let filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url);
  let extname = String(path.extname(filePath)).toLowerCase();
  let mimeTypes = {
    '.html': 'text/html',
    '.js': 'text/javascript',
    '.css': 'text/css',
    '.json': 'application/json',
    '.png': 'image/png',
    '.jpg': 'image/jpg',
    '.gif': 'image/gif',
    '.wav': 'audio/wav',
    '.mp4': 'video/mp4',
    '.woff': 'application/font-woff',
    '.ttf': 'application/font-ttf',
    '.eot': 'application/vnd.ms-fontobject',
    '.otf': 'application/font-otf',
    '.svg': 'application/image/svg+xml'
  };

  let contentType = mimeTypes[extname] || 'application/octet-stream';

  fs.readFile(filePath, (error, content) => {
    if (error) {
      if (error.code == 'ENOENT') {
        fs.readFile(path.join(__dirname, 'public', '404.html'), (error, content) => {
          res.writeHead(404, { 'Content-Type': 'text/html' });
          res.end(content, 'utf-8');
        });
      } else {
        res.writeHead(500);
        res.end(`Sorry, check with the site admin for error: ${error.code} ..\n`);
      }
    } else {
      res.writeHead(200, { 'Content-Type': contentType });
      res.end(content, 'utf-8');
    }
  });
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url) constructs the file path.
  • path.extname(filePath).toLowerCase() gets the file extension.
  • mimeTypes is an object mapping file extensions to MIME types.
  • contentType is set based on the file extension.
  • fs.readFile(filePath, callback) reads the file.
  • If the file is not found (ENOENT error), it serves a 404 page.
  • For other errors, it sends a 500 status code.
  • If the file is found, it sends the file content with the appropriate Content-Type.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Handling POST Requests

URL Parameters

To handle POST requests, you need to parse the request body. This can be done using the data and end events on the request object.

				
					const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST') {
    let body = '';

    req.on('data', chunk => {
      body += chunk.toString();
    });

    req.on('end', () => {
      res.end('Received POST data: ' + body);
    });
  } else {
    res.end('Send a POST request to see the data');
  }
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • The server checks if the request method is POST.
  • It listens for the data event to receive chunks of data and appends them to body.
  • When all data is received (end event), it sends the response with the received data.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Handling Form Data

To handle form data, you need to parse the request body. This can be done using the querystring module.

				
					const http = require('http');
const querystring = require('querystring');

const server = http.createServer((req, res) => {
  if (req.method === 'POST') {
    let body = '';

    req.on('data', chunk => {
      body += chunk.toString();
    });

    req.on('end', () => {
      const parsedBody = querystring.parse(body);
      res.end('Received Form Data: ' + JSON.stringify(parsedBody));
    });
  } else {
    res.end('Send a POST request to see the data');
  }
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • The querystring.parse(body) method parses the form data into an object.
  • The response sends the JSON representation of the parsed form data.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Handling JSON Data

To handle JSON data, you need to parse the request body as JSON.

				
					const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST') {
    let body = '';

    req.on('data', chunk => {
      body += chunk.toString();
    });

    req.on('end', () => {
      try {
        const parsedBody = JSON.parse(body);
        res.end('Received JSON Data: ' + JSON.stringify(parsedBody));
      } catch (e) {
        res.statusCode = 400;
        res.end('Invalid JSON');
      }
    });
  } else {
    res.end('Send a POST request to see the data');
  }
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • The JSON.parse(body) method parses the JSON data into an object.
  • If the JSON is invalid, it catches the error and sends a 400 status code with ‘Invalid JSON’.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Working with HTTP Headers

Handling JSON Data

HTTP headers can be set using the setHeader method on the response object.

				
					const http = require('http');

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('X-Custom-Header', 'CustomValue');
  res.end('Headers set');
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • res.setHeader('Content-Type', 'text/plain') sets the Content-Type header.
  • res.setHeader('X-Custom-Header', 'CustomValue') sets a custom header.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Reading Headers

HTTP headers can be read using the req.headers property.

				
					const http = require('http');

const server = http.createServer((req, res) => {
  const headers = req.headers;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(headers));
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • req.headers contains an object with all the request headers.
  • The response sends the JSON representation of the headers.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

HTTP Clients in Node.js

HTTP headers can be read using the req.headers property.

Making GET Requests

HTTP GET requests are used to request data from a specified resource. They are often used to retrieve data from a server without making any changes to the server’s state.

				
					const http = require('http');

// Define the options for the GET request
const options = {
  hostname: 'jsonplaceholder.typicode.com',
  port: 80,
  path: '/posts/1',
  method: 'GET',
};

// Create the request
const req = http.request(options, (res) => {
  let data = '';

  // Called when a data chunk is received
  res.on('data', (chunk) => {
    data += chunk;
  });

  // Called when the complete response has been received
  res.on('end', () => {
    console.log('Response from API:');
    console.log(JSON.parse(data));
  });
});

// Called if there is an error with the request
req.on('error', (e) => {
  console.error(`Problem with request: ${e.message}`);
});

// End the request
req.end();

				
			

Import the http module:

  • We import the http module using const http = require('http');. This module is built into Node.js and allows us to make HTTP requests.

Explanation :

Define the options for the request:

  • hostname: The domain name or IP address of the server (jsonplaceholder.typicode.com in this case).
  • port: The port number of the server (typically 80 for HTTP).
  • path: The path of the resource we want to fetch (/posts/1 fetches the post with ID 1).
  • method: The HTTP method for the request (GET in this case).

Create the request:

  • http.request(options, callback) creates an HTTP request with the specified options.
  • The callback function (res) handles the response from the server.

Handling the response:

  • res.on('data', callback): This event is fired when a chunk of data is received from the server. We concatenate each chunk to the data variable.
  • res.on('end', callback): This event is fired when the entire response has been received. Here, we parse the accumulated data as JSON and log it to the console.

Handling errors:

  • req.on('error', callback): If there is an error with the request, this event handler logs the error message.

Ending the request:

  • req.end(): Finally, we call req.end() to actually send the request to the server.

Making POST Requests

HTTP POST requests are used to send data to a server to create or update a resource. They are commonly used in form submissions, uploading files, and API interactions where data needs to be sent to the server.

Sending Data to an API

We’ll continue to use the JSONPlaceholder API to demonstrate how to send data using a POST request.

				
					const http = require('http');

// Define the data to be sent in the POST request
const postData = JSON.stringify({
  title: 'foo',
  body: 'bar',
  userId: 1,
});

// Define the options for the POST request
const options = {
  hostname: 'jsonplaceholder.typicode.com',
  port: 80,
  path: '/posts',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(postData),
  },
};

// Create the request
const req = http.request(options, (res) => {
  let data = '';

  // Called when a data chunk is received
  res.on('data', (chunk) => {
    data += chunk;
  });

  // Called when the complete response has been received
  res.on('end', () => {
    console.log('Response from API:');
    console.log(JSON.parse(data));
  });
});

// Called if there is an error with the request
req.on('error', (e) => {
  console.error(`Problem with request: ${e.message}`);
});

// Write the data to the request body
req.write(postData);

// End the request
req.end();

				
			

Explanation:

  • The http module is built into Node.js and is required to make HTTP requests.
  • postData: The data to be sent in the request body, formatted as a JSON string.
  • hostname: The server’s domain name.
  • port: The port number (80 for HTTP).
  • path: The endpoint path.
  • method: The HTTP method (POST for sending data).
  • headers: The headers for the request, including Content-Type and Content-Length.
  • http.request(options, callback): Creates the request with the specified options and a callback to handle the response (res).
  • res.on('data', callback): Listens for data chunks from the server. Each chunk is appended to the data variable.
  • res.on('end', callback): Listens for the end of the response. When the response is complete, the accumulated data is parsed as JSON and logged.
  • req.on('error', callback): Handles any errors that occur during the request.
  • req.write(postData): Writes the postData to the request body.
  • req.end(): Signals that the request is complete and sends it to the server.

Handling Errors in HTTP Server

When building an HTTP server, you need to handle various types of errors to ensure the server runs smoothly and can recover from unexpected issues. These errors might include network issues, invalid client requests, or internal server problems.

Example: Basic Error Handling in an HTTP Server

				
					const http = require('http');

// Create the server
const server = http.createServer((req, res) => {
  try {
    // Simulating an error
    if (req.url === '/error') {
      throw new Error('Simulated server error');
    }

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello, world!\n');
  } catch (err) {
    res.statusCode = 500;
    res.setHeader('Content-Type', 'text/plain');
    res.end(`Server Error: ${err.message}\n`);
  }
});

// Handle server errors
server.on('error', (err) => {
  console.error(`Server error: ${err.message}`);
});

// Start the server
server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • http.createServer((req, res) => { ... }): Creates an HTTP server and provides a callback to handle incoming requests.
  • if (req.url === '/error') { throw new Error('Simulated server error'); }: Simulates a server error when the /error endpoint is accessed.
  • try { ... } catch (err) { ... }: Wraps the request handling code in a try-catch block to catch any errors.
  • res.statusCode = 500: Sets the response status code to 500 (Internal Server Error).
  • res.setHeader('Content-Type', 'text/plain'): Sets the response content type to plain text.
  • res.end(Server Error: ${err.message}\n): Sends the error message as the response body.
  • server.on('error', (err) => { ... }): Listens for server-level errors and logs them to the console.
  • server.listen(3000, '127.0.0.1', () => { ... }): Starts the server on port 3000 and logs a message when it is running.

Handling Client Errors

Client errors occur when the client sends a malformed request or requests a resource that doesn’t exist. These errors are usually indicated by status codes in the 4xx range, such as 400 (Bad Request) or 404 (Not Found).

Handling Client Errors

				
					const http = require('http');

// Create the server
const server = http.createServer((req, res) => {
  // Handle different request paths
  if (req.url === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Welcome to the homepage!\n');
  } else if (req.url === '/error') {
    // Simulate a client error
    req.on('error', (err) => {
      res.statusCode = 400;
      res.setHeader('Content-Type', 'text/plain');
      res.end(`Client Error: ${err.message}\n`);
    });

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('No error occurred.\n');
  } else {
    // Handle 404 Not Found
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain');
    res.end('404 Not Found\n');
  }
});

// Handle server errors
server.on('error', (err) => {
  console.error(`Server error: ${err.message}`);
});

// Start the server
server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • if (req.url === '/') { ... } else if (req.url === '/error') { ... } else { ... }: Checks the request URL and handles different paths.
  • res.statusCode = 200: Sets the response status code to 200 (OK).
  • res.setHeader('Content-Type', 'text/plain'): Sets the response content type to plain text.
  • res.end('Welcome to the homepage!\n'): Sends the response body.
  • req.on('error', (err) => { ... }): Listens for errors on the client request.
  • res.statusCode = 400: Sets the response status code to 400 (Bad Request).
  • res.setHeader('Content-Type', 'text/plain'): Sets the response content type to plain text.
  • res.end(Client Error: ${err.message}\n): Sends the error message as the response body.
  • res.statusCode = 404: Sets the response status code to 404 (Not Found).
  • res.setHeader('Content-Type', 'text/plain'): Sets the response content type to plain text.
  • res.end('404 Not Found\n'): Sends the 404 Not Found message as the response body.
  • server.on('error', (err) => { ... }): Listens for server-level errors and logs them to the console.
  • server.listen(3000, '127.0.0.1', () => { ... }): Starts the server on port 3000 and logs a message when it is running.

Middleware in Node.js

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. They can execute code, modify the request and response objects, end the request-response cycle, and call the next middleware function.

Creating Middleware Functions

				
					const http = require('http');

const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
};

const server = http.createServer((req, res) => {
  const next = () => {
    res.statusCode = 200;
    res.end('Hello, Middleware');
  };

  logger(req, res, next);
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • logger is a middleware function that logs the request method and URL.
  • The next function calls the next middleware or the final handler.
  • The logger middleware is called before sending the response.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

Using Third-Party Middleware

You can use third-party middleware packages like morgan for logging and body-parser for parsing request bodies.

				
					const http = require('http');
const morgan = require('morgan');
const finalhandler = require('finalhandler');

const logger = morgan('combined');

const server = http.createServer((req, res) => {
  const next = finalhandler(req, res);
  logger(req, res, next);
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

				
			

Explanation:

  • morgan is a logging middleware.
  • finalhandler handles the final response.
  • The logger middleware is used to log requests.
				
					// Output //
Server running at http://127.0.0.1:3000/

				
			

In this chapter, we covered:

  • Creating a basic HTTP server
  • Handling different routes and query parameters
  • Serving static files
  • Handling POST requests and parsing request bodies
  • Working with HTTP headers
  • Making HTTP requests as a client
  • Error handling in HTTP servers and clients
  • Using middleware functions

With the knowledge gained from this chapter, you should be well-equipped to handle any HTTP-related tasks in Node.js. Keep experimenting and exploring to master the full potential of the http module.

The http module in Node.js provides robust capabilities for creating HTTP servers and clients. By understanding the basic and advanced features of this module, you can build a wide range of server-side applications, from simple static file servers to complex web applications handling dynamic content and APIs.Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India