Node.Js Http

Node.Js has rich http protocol support built in. Functions, related to serving http are gathered in node:http module.

To import it using common-js:

const http = require('node:http');

Or es6 imports:

import http from 'node:http';

Http Server

http module contains default implementation of an http server. To create simple version of it use http.createServer:

const server = http.createServer(
  (req: IncomingMessage, res: ServerResponse) => {
    console.info(`serving request: ${req.method}: ${req.url}`);

    res.write("RESPONSE", (err) => {
      if (err) {
        console.error(err);
      }
    });

    res.end();
  }
);

server.listen(8000, () => { console.log("listening on port 8000"); });

This code creates http server, which will listen for requests on port 8000.

Here createServer has signature:

function createServer(requestListener?: RequestListener): Server;
type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;

To parse url there is node:url module:

const reqUrl: UrlWithParsedQuery = url.parse(req.url, true);
console.info(reqUrl.pathname);
for (const val in reqUrl.query) {
    console.info(`${val} => ${reqUrl.query[val]}`);
}

where UrlWithParsedQuery:

interface Url {
    auth: string | null;
    hash: string | null;
    host: string | null;
    hostname: string | null;
    href: string;
    path: string | null;
    pathname: string | null;
    protocol: string | null;
    search: string | null;
    slashes: boolean | null;
    port: string | null;
    query: string | null | ParsedUrlQuery;
}
interface UrlWithParsedQuery extends Url {
    query: ParsedUrlQuery;
}

Simple html server example:

Let's create a simple implementation of an html server, which will serve html file depending on url path.

import http, { IncomingMessage, ServerResponse } from "node:http";
import url, { UrlWithParsedQuery } from "node:url";
import fs from "node:fs";
import path from "node:path";

// this function constructs path in local file system 
// to locate particular html file by url path
const getServedFileName = (requestPath: string) => {
  if (requestPath === "/") {
    return path.join("..", "public", "index.html");
  }
  return path.join("..", "public", `${requestPath}.html`);
};

// creating http server
const server = http.createServer(
  (req: IncomingMessage, res: ServerResponse) => {
    if (!req.url) {
      return res.writeHead(400, "Bad request");
      return res.end();
    }

    const requestUrl: UrlWithParsedQuery = url.parse(req.url, true);
    const requestPath = requestUrl.pathname;
    console.info("serving: " + requestPath);

    if (!requestPath) {
      res.writeHead(400, "Bad request");
      return res.end();
    }

    // generate path to correct html page file
    const fileName = getServedFileName(requestPath);

    // reading file from local file system
    fs.readFile(fileName, (err, data) => {
      if (err) {
        res.writeHead(500, "Server error");
        console.error(err);
        return res.end();
      }

      res.writeHead(200, "OK");
      res.write(data, (err) => {
        if (err) {
          console.error(`Error serving request ${err}`);
        }
      });
      return res.end();
    });
  }
);

// starting the server
server.listen(8000, () => {
  console.log("listening on port 8000");
});

This implementation assumes, that html files are placed in a folder named public, which located one level up from our running server.

HTTP Requests

Node.Js http module has an ability to perform HTTP requests. To do this, use http.request function.

For example:

function makeRawHttpRequest<T>(
  host: string,
  urlPath: string
): Promise<T> {
  const options = {
    hostname: host,
    path: urlPath,
    method: "GET",
  };

  return new Promise<T>((resolve, reject) => {
    http
      .request(options, (res) => {
        let data = "";

        res.on("data", (chunk) => {
          data += chunk;
        });

        res.on("end", () => {
          const result = JSON.parse(data) as T;
          console.log("Body:", result);
          resolve(result);
        });
      })
      .on("error", (err) => {
        console.log("Error: ", err);
        reject(err);
      })
      .end();
  });
}

But this requires some boilerplate code to manually handle stream events and parse data. There are many third party libraries, like axios, which simplify this process.

Plan

  • http2
  • https
  • axios