File size: 3,118 Bytes
1628025
 
 
 
 
433085e
e9affa5
1628025
e9affa5
 
 
 
 
1628025
 
 
 
 
 
 
 
 
 
 
e9affa5
 
 
 
 
1628025
e9affa5
1628025
e9affa5
 
 
 
 
 
 
1628025
 
e9affa5
433085e
 
e9affa5
1628025
e9affa5
 
 
 
 
 
 
1628025
e9affa5
 
3787f0d
 
 
e9affa5
3787f0d
e9affa5
 
 
 
 
 
 
3787f0d
 
 
1628025
 
 
 
e9affa5
 
 
 
1628025
e9affa5
 
 
3787f0d
fe4d244
8b3449a
96594d4
1628025
 
e9affa5
 
 
 
 
 
1628025
 
8b3449a
1628025
 
ac9dbd5
8b3449a
ac9dbd5
 
 
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
import { Router, Express } from "express";

import * as glob from "glob";
import path from "path";
import { BaseController } from "./lib/controllers/controller.base";
import { validationErrorHandler } from "./helpers/validation.helper";
import { JsonResponse } from "@lib/responses/json-response";

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

  await importControllers(mainRouter);
  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 = (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);

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

  // Error handler
  router.use((err, req, res, next) => {
    try {
      err.message = JSON.parse(err.message);
    } catch (error) {}

    JsonResponse.error(
      {
        error: err.message || "Internal Server Error",
        status: err.status || 500,
      },
      res
    );

    console.error(err.message, err.stack);
  });
};

/* 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();

  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);
    })
  );
};

/**
 * 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;
};