File size: 3,771 Bytes
1628025
 
 
 
fe17679
1628025
433085e
e9affa5
67bacb2
fe17679
1628025
e9affa5
 
 
 
 
1628025
 
 
 
721abf7
1628025
 
 
 
 
 
e9affa5
 
 
 
 
721abf7
e9affa5
1628025
e9affa5
 
 
 
 
 
 
1628025
 
e9affa5
433085e
 
721abf7
fe17679
 
 
5d056c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fe17679
721abf7
e9affa5
721abf7
e9affa5
 
 
 
 
 
 
1628025
e9affa5
 
67bacb2
1628025
 
 
 
e9affa5
 
 
 
1628025
e9affa5
 
 
3787f0d
fe4d244
8b3449a
96594d4
1628025
 
e9affa5
 
 
 
 
 
1628025
 
8b3449a
fda6ff3
1628025
 
ac9dbd5
8b3449a
ac9dbd5
 
 
1628025
 
 
fda6ff3
1628025
 
e9affa5
 
 
 
 
1628025
 
 
ac9dbd5
 
1628025
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { Router, Express } from "express";

import * as glob from "glob";
import path from "path";
import swaggerUi from "swagger-ui-express";
import { BaseController } from "./lib/controllers/controller.base";
import { validationErrorHandler } from "./helpers/validation.helper";
import { JsonResponse } from "@lib/responses/json-response";
import { errorHandlerMiddleware } from "middlewares/error-handler.middleware";
import { swaggerRegistry } from "@lib/swagger/swagger";

/**
 * Sets the routes for the Express app.
 *
 * @param app - The Express app.
 */
export const setAppRoutes = async (app: Express) => {
  const mainRouter = Router();

  await importControllers(mainRouter);
  await setCustomRoutes(mainRouter);

  app.use("/api/v1", mainRouter);
};

/* custom routes */

/**
 * Sets custom routes for the router.
 *
 * @param router - The router object to set the routes on.
 */
const setCustomRoutes = async (router: Router) => {
  // Health check route
  router.get("/health", (_req: any, res: any) => {
    JsonResponse.success(
      {
        message: "Server is up!",
        data: { success: true },
      },
      res
    );
  });

  // Validation error handler
  router.use(validationErrorHandler);

  // docs
  router.use(
    "/docs",
    swaggerUi.serve,
    swaggerUi.setup(swaggerRegistry.generateSwaggerDocument(), {
      customCss: ".swagger-ui .topbar { display: none }",
      customSiteTitle: "API Documentation",
      swaggerOptions: {
        layout: "StandaloneLayout",
        deepLinking: true,
        docExpansion: "none",
        filter: true,
        tagsSorter: "alpha",
        operationsSorter: "alpha",
        showMutatedRequest: true,
        showMutatedResponse: true,
        showRequestDuration: true,
        persistAuthorization: true,
        displayRequestDuration: true,
        withCredentials: true,
      },
    })
  );

  // Invalid URL handler
  router.all("*", (req: any, res: any) => {
    JsonResponse.error(
      {
        error: "Invalid URL!",
        status: 404,
      },
      res
    );
  });

  // Error handler
  router.use(errorHandlerMiddleware);
};

/* importing all controllers */

/**
 * Finds all controller files in the project.
 * @returns An array of strings representing the absolute paths of the controller files.
 */
const findControllerFiles = (): string[] => {
  const controllersPath = path
    .relative(process.cwd(), path.join(__dirname, "**/*.controller.{ts,js}"))
    .replace(/\\/g, "/");

  return glob.sync(controllersPath, {}).map((file) => {
    return path.resolve(file);
  });
};

/**
 * Imports controller classes from files, sets up routes for each controller,
 * and adds them to the provided router.
 *
 * @param router - The router to add the routes to.
 */
const importControllers = async (router: Router) => {
  const files = findControllerFiles();

  console.log("importing controllers...");
  await Promise.all(
    files.map(async (file) => {
      const controllerClass = await importController(file);

      if (!controllerClass) return;
      const controller: BaseController = new (controllerClass as any)();
      controller.setRoutes();
      router.use(controller.prefix, controller.router);
    })
  );
  console.log("controllers imported!");
};

/**
 * Imports a module from a file and returns the first controller that extends BaseController.
 * @param file - The path to the file containing the module.
 * @returns The first controller that extends BaseController.
 */
const importController = async (file: string) => {
  const controllers = Object.values(await import(file));
  return controllers.find(
    (controller: { prototype: typeof BaseController }) =>
      controller.prototype instanceof BaseController
  ) as typeof BaseController;
};