beginner

Creating a proper server


So now we have a working server that handles routes but it is not able to grow with more routes and logic and we are not using classes. So let us rewrite what we have so far and make it even better.

Ignitor

We will move all of our server logic to a new class called Ignitor but you can call it however you want.

Ignitor.js

const http = require("http");
const router = require("./routes.js");

const PORT = 3000;

class Ignitor {
  #instance;
  constructor() {
    if (this.#instance) {
      throw new Error("New instance cannot be created.");
    }

    this.#instance = this;
  }

  start() {
    http.createServer(router).listen(PORT);
  }
}

module.exports = new Ignitor();

The only new thing in this code is a Singleton pattern which is basically a way to instantiate only one object of a given class. The reason for this is that we want to share some resources. Most commonly it is used for database connections because you only want to have one such connection. Here we are using it because we want only one object to be our server and be our single point of entry for our server.

As you see it is very simple to create a singleton, we limit our constructor to only create one instance and we immediately instantiate an object that we later export with module.exports to allow it to be required in other files.

As for requiring those files we use relative file path meaning that ./ inside require means “look in this directory” so our './routes.js' means “load routes.js file from current folder”

We will move our router function in a separate file called routes.js and we will export it at the end of the file.

routes.js

function router(req, res) {
  const protocol = req.protocol ?? "http";
  const baseUrl = `${protocol}://${req.headers.host}/`;
  const reqUrl = new URL(req.url, baseUrl);
  const path = reqUrl.pathname;

  switch (path) {
    case "/":
      if (req.method !== "GET") {
        return handleUnsupportedMethod(res);
      }
      res.writeHead(200, { "Content-Type": "text/plain" });
      res.end("Welcome to the Home Page!");
      break;
    case "/about":
      if (req.method !== "GET") {
        return handleUnsupportedMethod(res);
      }
      res.writeHead(200, { "Content-Type": "text/plain" });
      res.end("This is the About Page!");
      break;
    case "/posts":
      if (req.method !== "POST") {
        return handleUnsupportedMethod(res);
      }
      return handlePostMethod(req, res);
      break;
    default:
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("404 Not Found");
      break;
  }
}

module.exports = router;

In our index.js that we had so far we will import our Ignitor and start it. These three files will be in the same folder.

index.js

const Server = require("./Ignitor.js");
Server.start();

Now we can run our server with command node index.js

Folder structure

index.js
routes.js
Ignitor.js
Previous HTTP request methods | Events and streams
Next Creating proper routes