Setting up the  web server layer

Setting up the web server layer

Clean Architecture Series - Frameworks Layer

The communication between the underlying application and clients (such as web browsers or mobile apps) in the outside world is handled by the web server layer. It receives queries from other sources, processes them, and sends back the relevant answers. It includes parts such as views, middleware, controllers, and routers.

We will start creating the folder structure for our web server layer. So, go to frameworks folder and create a new folder named "webserver" with a subfolder named "express".

Server Interface

Before setup the web server framework, we will create an interface which ensure that any server implementing the IServer interface contract. So, create a file named "server.interface.ts" into the "webserver" folder:

// .src/frameworks/webserver/server.interface.ts
export interface IServer {
  port: number;
  bootstrap: () => Promise<void>;
  listen: () => Promise<void>;
}

Let's explain the interface:

port: Define port number which the server use to listens the connections.

bootstrap: The bootstrap method allows to implement what "staffs" the server needs to do before start. For example: Load middlewares or routes.

listen: The listen method allows to implement how the frameworks start listening the connections.

ExpressJs Framework

For our project we will use ExpressJs as the web framework:

Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications...

ExpressRouter

To define how our web server handles client requests we have to implement the ExpressJs Router. So, create a file named "api.router.ts" into the "express" folder:

// .src/frameworks/webserver/express/api.router.ts
import { CreatePolicyController } from "@/adapters/controllers/policy/create-policy.controller";
import { ExpressAdapter } from "@/adapters/http/express.adapter";
import { IHttpRequest } from "@/adapters/http/http-request.interface";
import { SqliteDb } from "@/frameworks/persistence/db/sqlite/sqlite.db";
import { PolicyRepository } from "@/frameworks/persistence/repositories/policy/policy.repository";
import { Router } from "express";

// create the router object
const router = Router();
// get the sqlite database instance
const sqliteDb = SqliteDb.getInstance();
// create the repository and inject the db dependency
const policyRepository = new PolicyRepository(sqliteDb);
// create the controller and inject the repository dependency
const createPolicyController = new CreatePolicyController(policyRepository);

export const apiRouter = () => {
  router
    .route("/policy")
    .post(
      // adapting the incoming request and calling the controller function
      ExpressAdapter.controller((httpRequest: IHttpRequest) =>
        createPolicyController.execute(httpRequest)
      )
    );
  return router;
};

As you remember, the repository and controller are using "Inversion of Control" (IoC) and DI (Dependency Injection) for this reason, before create every object we have to satisfy their constructor dependencies.

The "apiRouter" constant encapsulates the logic to handle the "/policy" route for "POST" http method. Also, we use the "ExpressAdapter" to adapt the incoming request and call the controller function and inject the httpRequest object.

Express Server

To implement express as web server we need to create a file named "server.ts" into the "express" folder:

// .src/frameworks/webserver/express/server.ts
import express from "express";
import { apiRouter } from "./api.router";
import { IServer } from "../server.interface";

export class Server implements IServer {
  port: number;
  private framework: express.Application;
  constructor(port: number) {
    this.port = port;
    this.framework = express();
  }

  async bootstrap(): Promise<void> {
    // Builtin Express Middleware
    this.framework.use(express.json());

    // Routers
    this.framework.use(apiRouter());
  }

  async listen(): Promise<void> {
    this.framework.listen(this.port);
  }
}

bootstrap: The "bootstrap" method is setting the express json middleware which parses incoming requests with JSON payloads. And also, this method is loading the API Routes.

listen: The "listen" method encapsulate the logic related to how the "ExpressJs Framework" needs to be configured to listening for connections.

The web server layer is isolated from the core business logic and focuses solely on handling the communication aspects.

And thats all for the web server layer, see you in the next article.

Did you find this article valuable?

Support Max Martínez Cartagena by becoming a sponsor. Any amount is appreciated!