## Running Our Server

<!-- Learn how to run the server and listen for incoming requests in Node.js. Implement a `run` function that accepts a router and a port number as arguments. Understand how to use the `createServer` function from the `node:http` module to create an HTTP server. -->

We have a working implementation of our `TrieRouter` class, which has enough functionality to handle routing for our server. But, we don't have a way to run our server or listen for requests yet.

In this chapter, we will implement a `run` function that accepts a router (`TrieRouter`) and a port (`number`) argument. This function will serve as the entry point of our server code, allowing us to handle incoming requests and route them to the appropriate handlers defined in our router.

But before that, let's refactor our code a little bit. We're going to rename the `TrieRouter` class to `Router`. Secondly, we're going to add JSDoc comments to all the methods in the `Router` class, to make our lives easier with the auto-completion and documentation.

### Refactoring the `TrieRouter` class

```js
const HTTP_METHODS = { ... } // Remains unchanged

class RouteNode {
  constructor() {
    /** @type {Map<String, RouteNode>} */
    this.children = new Map();

    /** @type {Map<String, Function>} */
    this.handler = new Map();

    /** @type {Array<String>} */
    this.params = [];
  }
}


class Router {
  constructor() {
    /** @type {RouteNode} */
    this.root = new RouteNode();
  }

  /**
   * @param {String} path
   * @param { 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' } method
   * @param {Function} handler
   */
  #verifyParams(path, method, handler) { ... }


  /**
   * @param {String} path
   * @param { 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' } method
   * @param {Function} handler
   */
  #addRoute(path, method, handler) { ... }

  /**
   * @param {String} path
   * @param { 'GET' | 'POST' | 'PUT ' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT ' | 'TRACE ' } method
   * @returns { { params: Object, handler: Function } | null }
   */
  findRoute(path, method) { ... }

   /**
   * @param {String} path
   * @param {Function} handler
   */
  get(path, handler) {
    this.#addRoute(path, HTTP_METHODS.GET, handler);
  }

  /** For POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE, we are going to re-use the same JSDoc comment as `get` method */

  /**
   * @param {RouteNode} node
   * @param {number} indentation
   */
  printTree(node = this.root, indentation = 0) { ... }
}
```

As you can see, we're repeating this JSDoc comment for a couple of methods:

```js
/**
 * @param {String} path
 * @param { 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' } method
 * @param {Function} handler
 */
```

This is not a good practice. Instead we can make use of something called **Type Aliases**.

Type aliases are a way to give a type a name, just like a variable. Each type **should be** distinct. They are exactly the same as the original type, but with a different name. This is useful when you want to refer to the same type multiple times and don't want to repeat the same type definition.

### Type Aliases

Let's add a type alias for the HTTP methods:

```js
/**
 * @typedef { 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' } HttpMethod
 */
```

And, to use this type alias in our JSDoc comments:

```js
/**
* @param {String} path
* @param {HttpMethod} method
* @param {Function} handler
*/
#verifyParams(path, method, handler) { ... }

/**
 * @param {String} path
 * @param {HttpMethod } method
 * @param {Function} handler
 */
#addRoute(path, method, handler) { ... }

/** And so on... */
```

But there's a small issue. We have defined the `HttpMethod` type alias in the same file as the `Router` class. This will make it impossible to use the `HttpMethod` type alias in other files. To fix this, we can create a new file `globals.js` and move all the global type aliases here.

```js
// file: globals.js

/**
 * @typedef { 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE' } HttpMethod
 */
```

Now you'd be able to use the `HttpMethod` type alias in any file. That's enough refactoring for now.

### The `run` function

```js
const { createServer } = require("node:http");

/**
 * Run the server on the specified port
 * @param {Router} router - The router to use as the main request handler
 * @param {number} port - The port to listen on
 */
function run(router, port) {
  if (!(router instanceof Router)) {
    throw new Error("`router` argument must be an instance of Router");
  }

  if (typeof port !== "number") {
    throw new Error("`port` argument must be a number");
  }

  createServer(function _create(req, res) {
    const route = router.findRoute(req.url, req.path);

    if (route?.handler) {
      req.params = route.params;
      route.handler(req, res);
    } else {
      res.writeHead(404, null, { "content-length": 9 });
      res.end("Not Found");
    }
  }).listen(port);
}
```

Let's go through the code line by line:

```js
const { createServer } = require("node:http");
```

We're importing the `createServer` function that the `node:http` module provides. This function is used to create an HTTP server that listens for requests on a specified `port`. We already created a demo server using `http.createServer()` in [HTTP Deep Dive](https://github.com/ishtms/learn-nodejs-hard-way/blob/master/chapters/ch05.0-http-deep-dive.md).

```js
function run(router, port) { ... }
```

This is going to be the main entry point of our library. The `run` function is accepts two arguments: `router` and `port`. The `router` will be an instance of the `Router` class that we defined earlier, and the `port` will be the port number on which the server will listen for incoming requests.

```js
if (!(router instanceof Router)) {
  throw new Error("`router` argument must be an instance of Router");
}

if (typeof port !== "number") {
  throw new Error("`port` argument must be a number");
}
```

Some basic type checking to ensure that the `router` argument is an instance of the `Router` class and the `port` argument is a number.

```js
createServer(function _create(req, res) { ... }).listen(port);
```

We're creating an HTTP server using the `createServer` function. To re-iterate, the `createServer` function takes a single argument\*, which is a callback function. The callback function will receive two arguments: `req` (the `Http.IncomingMessage` object) and `res` (the `Http.ServerResponse` object).

```js
const route = router.findRoute(req.url, req.path);

if (route?.handler) {
  req.params = route.params;
  route.handler(req, res);
} else {
  res.writeHead(404, null, { "Content-Length": 9 });
  res.end("Not Found");
}
```

We're calling the `findRoute` method on the `router` object to find the route that matches the incoming request. The `findRoute` method will return an object with two properties: `handler` and `params`. If a route is found, we'll call the `handler` function with the `req` and `res` objects. If no route is found, we'll return a `404 Not Found` response.

Inside the `if` statement, we're attaching a new property `req.params` to the `req` object. This property will contain the parameters extracted from the URL. The client can easily access the parameters using `req.params`.

You might have noticed that we're using a hard-coded `Content-Length` header with a value of `9`. This is because, if we do not specify the `Content-Length` header, the response headers will include a header `Transfer-Encoding: chunked`, which has a performance impact. We discussed about this in a previous chapter - [Chunks, oh no!](chapters/ch06.01-basic-router-implementation.md#chunks-oh-no-)

That's it! We have implemented the `run` function, which will allow us to run our server and listen for incoming requests. In the next chapter, we'll implement a simple server using our `Router` class and the `run` function.

> \*The callback function has multiple overloads, i.e it has a couple more function signatures. But for now, we're only interested in the one that takes a single callback function.
