codeweaver 1.0.15 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ {
2
+ "cSpell.words": ["microframework"]
3
+ }
package/README.md CHANGED
@@ -2,25 +2,19 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- **Codeweaver** is a lightweight framework built on top of `Express` and `TypeScript`, integrating `Swagger` for API documentation. The application utilizes `async handlers` for improved error management and follows a modular structure for routers, enabling easy expansion and organization of the application.
5
+ **Codeweaver** is a lightweight microframework created with `Express`, `TypeScript`, and `Zod` (v4), seamlessly integrated with `Swagger` for comprehensive API documentation. Its modular architecture for routers promotes scalability and organized development, making it easy to expand and maintain.
6
6
 
7
- ## Features
8
-
9
- - **Modular Router Structure**: Each router is automatically imported and mounted, providing clean separation of endpoints and logic.
10
- - **Express Framework**: A lightweight web application framework for building web applications in Node.js.
11
- - **TypeScript**: Provides strong typing for better development experience and less runtime errors.
12
- - **Swagger Integration**: Automatically generates interactive API documentation, making it easy for developers and consumers to understand the available endpoints.
13
- - **Async Handlers**: Supports async/await syntax for writing cleaner and more maintainable asynchronous code without deeply nested callbacks.
14
-
15
- ## Technologies Used
7
+ ## Features and Technologies Used
16
8
 
17
9
  - **Node.js**
18
- - **Express**
19
- - **TypeScript**
20
- - **Zod** (for input validation)
21
- - **ts-zod-decorators** (for validation using Zod with decorators)
22
- - **utils-decorators** (for middleware utilities like throttling and error handling)
23
- - **Swagger** (for API documentation)
10
+ - **Express**: A lightweight web framework for building server-side applications in Node.js.
11
+ - **TypeScript**: Adds strong typing for enhanced development experience and reduced runtime errors.
12
+ - **Modular Router Structure**: Automates importing and mounting routers, ensuring a clean separation of endpoints and logic for easier scalability.
13
+ - **Swagger Integration**: Automatically generates interactive API documentation, facilitating easier understanding of available endpoints for developers and consumers.
14
+ - **Async Handlers**: Utilizes async/await syntax for cleaner, more maintainable asynchronous code without callback nesting.
15
+ - **Zod**: Implements schema validation for input data.
16
+ - **ts-zod-decorators**: Enables validation using Zod schemas through decorators.
17
+ - **utils-decorators**: Provides middleware utilities such as throttling and error handling for a more robust application.
24
18
 
25
19
  ## Installation
26
20
 
@@ -29,6 +23,7 @@ To get started with the project, follow these steps:
29
23
  1. **Clone the repository**:
30
24
 
31
25
  ```bash
26
+ npm install -g codeweaver
32
27
  npx create-codeweaver-app my-app
33
28
  cd my-app
34
29
  ```
@@ -51,63 +46,139 @@ To get started with the project, follow these steps:
51
46
 
52
47
  ```bash
53
48
  npm run build
49
+ npm run serve
54
50
  ```
55
51
 
56
52
  ## Sample Project Structure
57
53
 
58
54
  **/src**
59
55
  ├── **/routers** `Directory containing all router files`
60
- │ ├── **/user** `Routers for user-related endpoints`
61
- │ │ ├── user_router1.ts `/user/user_router1`
62
- │ │ ├── user_router2.ts `/user/user_router2`
56
+ │ ├── **/users** `Routers for user-related endpoints`
57
+ │ │ ├── index.router.ts `/users`
58
+ │ │ ├── user-router2.router.ts `/users/user-router2`
63
59
  │ │ ├── user.controller.ts
64
60
  │ │ ├── user.service.ts
65
61
  │ │ └── user.dto.ts
66
- │ ├── **/product** `Routers for product-related endpoints`
67
- │ │ ├── index.ts `/product`
68
- │ │ ├── product_test.spec.ts
62
+ │ ├── **/products** `Routers for product-related endpoints`
63
+ │ │ ├── index.router.ts `/products`
69
64
  │ │ ├── product.controller.ts
70
65
  │ │ ├── product.service.ts
71
- │ │ ├── **/dto**
66
+ │ │ ├── **/dtos**
72
67
  │ │ │ └── product.dto.ts
73
- ├── **/order** `Routers for order-related endpoints`
74
- ├── index.ts `/order`
75
- │ │ ├── order_test.spec.ts
68
+ | | └── product-types.dto.ts
69
+ │ ├── **/orders** `Routers for order-related endpoints`
70
+ │ │ ├── index.router.ts `/orders`
76
71
  │ │ ├── order.controller.ts
77
- │ │ └── order.service.ts
78
- └── index.ts `Home page`
72
+ │ │ ├── order.controller.spec.ts
73
+ ├── order.service.ts
74
+ │ │ └── order.service.spec.ts
75
+ │ └── index.router.ts `Home page`
76
+ │ └── app.controller.ts `Home page`
79
77
  ├── app.ts `Main application file`
80
78
  ├── config.ts `Application configuration file`
81
79
  └── ... `Other files (middleware, models, etc.)`
82
80
 
83
81
  ### Router Directory
84
82
 
85
- Each router file in the `/routers` directory is organized to handle related endpoints. The `app.ts` file automatically imports all routers and mounts them to the main Express application, making it simple to add new routes without modifying central files.
83
+ Each router file in the `/routers` directory is organized to handle related endpoints. The `app.ts` file automatically imports all routers and mounts them on the main Express application, making it straightforward to add new routes without touching central code.
86
84
 
87
- Files that end with `.controller`, `.service`, `.spec`, `.dto`, `.middleware`, `.error`, or `.decorator`, as well as those that start with `_` or `@`, are excluded from the router list and can be utilized for various other purposes within the application.
85
+ Files ending with `.router.ts` or `.router.js` are automatically included in the router list and can be reused for various purposes within the application.
88
86
 
89
87
  Example of a basic router:
90
88
 
91
89
  ```typescript
92
90
  import { Router, Request, Response } from "express";
93
91
  import asyncHandler from "express-async-handler";
92
+ import UserController from "./user.controller";
94
93
 
95
94
  const router = Router();
95
+ const userController = new UserController();
96
+
97
+ /**
98
+ * @swagger
99
+ * /users:
100
+ * post:
101
+ * summary: Create a user
102
+ * description: Create a new user.
103
+ * consumes:
104
+ * - application/json
105
+ * produces:
106
+ * - application/json
107
+ * parameters:
108
+ * - in: body
109
+ * name: user
110
+ * required: true
111
+ * schema:
112
+ * type: object
113
+ * required:
114
+ * - username
115
+ * - email
116
+ * - password
117
+ * properties:
118
+ * username:
119
+ * type: string
120
+ * minLength: 3
121
+ * example: JessicaSmith
122
+ * email:
123
+ * type: string
124
+ * format: email
125
+ * example: user@example.com
126
+ * password:
127
+ * type: string
128
+ * minLength: 6
129
+ * example: securePassword123
130
+ * responses:
131
+ * 201:
132
+ * description: User created
133
+ */
134
+ router.post(
135
+ "/",
136
+ asyncHandler(async (req: Request, res: Response) => {
137
+ const user = await userController.create(req.body);
138
+ res.status(201).json(user);
139
+ })
140
+ );
96
141
 
97
142
  /**
98
143
  * @swagger
99
- * /:
144
+ * /users/{id}:
100
145
  * get:
101
- * summary: Get the home page
102
- * description: Returns the home page.
146
+ * summary: Get a user by ID
147
+ * parameters:
148
+ * - name: id
149
+ * in: path
150
+ * required: true
151
+ * description: The ID of the product
152
+ * schema:
153
+ * type: integer
103
154
  * responses:
104
155
  * 200:
105
- * description: home page
156
+ * description: A user object
157
+ * 404:
158
+ * description: user not found
159
+ */
160
+ router.get(
161
+ "/:id",
162
+ asyncHandler(async (req: Request, res: Response) => {
163
+ const user = await userController.get(req.params.id);
164
+ res.json(user);
165
+ })
166
+ );
167
+
168
+ /**
169
+ * @swagger
170
+ * /users:
171
+ * get:
172
+ * summary: Get users
173
+ * description: Returns a list of user objects.
174
+ * responses:
175
+ * 200:
176
+ * description: A list of user objects
106
177
  */
107
178
  router.get(
108
179
  "/",
109
180
  asyncHandler(async (req: Request, res: Response) => {
110
- res.send("Home");
181
+ res.json(await userController.getAll());
111
182
  })
112
183
  );
113
184
 
@@ -131,13 +202,27 @@ Here’s a brief breakdown of key components used in the `UserController`:
131
202
  ```typescript
132
203
  import { z } from "zod";
133
204
 
134
- export const createUserDto = z.object({
205
+ /**
206
+ * Zod schema for User entity
207
+ * @typedef {Object} ZodUser
208
+ * @property {number} id - Unique identifier (min 1)
209
+ * @property {string} username - Username (min 3 chars)
210
+ * @property {string} email - Valid email format
211
+ * @property {string} password - Password (min 6 chars)
212
+ */
213
+ export const ZodUser = z.object({
214
+ id: z.number().min(1).int(),
135
215
  username: z.string().min(3),
136
- email: z.string().email(),
216
+ email: z.email(),
137
217
  password: z.string().min(6),
138
218
  });
139
219
 
140
- export type CreateUser = z.infer<typeof createUserDto>;
220
+ export const ZodUserCreationDto = ZodUser.omit({ id: true });
221
+ export const ZodUserDto = ZodUser.omit({ password: true });
222
+
223
+ export type User = z.infer<typeof ZodUser>;
224
+ export type UserCreationDto = z.infer<typeof ZodUserCreationDto>;
225
+ export type UserDto = z.infer<typeof ZodUserDto>;
141
226
  ```
142
227
 
143
228
  - **Throttling and Rate Limiting**: The `@rateLimit` decorator is applied to safeguard the application's endpoints from abuse by limiting how frequently a particular method can be invoked.
@@ -149,37 +234,157 @@ By using a well-organized controller structure, this project makes it easier to
149
234
  Here is a quick reference to the UserController in practice:
150
235
 
151
236
  ```typescript
152
- import { Validate, ZodInput } from "ts-zod-decorators";
153
- import { createUserDto, CreateUser } from "./dto/user.dto";
154
- import { onError, rateLimit } from "utils-decorators";
237
+ import {
238
+ User,
239
+ ZodUserCreationDto,
240
+ UserCreationDto,
241
+ UserDto,
242
+ } from "./dto/user.dto";
243
+ import { memoizeAsync, onError, rateLimit, timeout } from "utils-decorators";
244
+ import { Validate, ZodInput } from "ts-zod4-decorators";
245
+ import { ResponseError } from "@/types";
246
+ import { parseId } from "@/utilities/error-handling";
247
+ import config from "@/config";
248
+
249
+ // Array to store users (as a mock database)
250
+ const users = [
251
+ {
252
+ id: 1,
253
+ username: "johndoe",
254
+ email: "johndoe@gmail.com",
255
+ password: "S3cur3P@ssw0rd",
256
+ },
257
+ {
258
+ id: 2,
259
+ username: "janesmith",
260
+ email: "janesmith@yahoo.com",
261
+ password: "P@ssw0rd2024",
262
+ },
263
+ {
264
+ id: 3,
265
+ username: "michael89",
266
+ email: "michael89@hotmail.com",
267
+ password: "M1chael!2024",
268
+ },
269
+ {
270
+ id: 4,
271
+ username: "lisa.wong",
272
+ email: "lisa.wong@example.com",
273
+ password: "L1saW0ng!2024",
274
+ },
275
+ {
276
+ id: 5,
277
+ username: "alex_k",
278
+ email: "alex.k@gmail.com",
279
+ password: "A1ex#Key2024",
280
+ },
281
+ {
282
+ id: 6,
283
+ username: "emilyj",
284
+ email: "emilyj@hotmail.com",
285
+ password: "Em!ly0101",
286
+ },
287
+ {
288
+ id: 7,
289
+ username: "davidparker",
290
+ email: "david.parker@yahoo.com",
291
+ password: "D@v!d2024",
292
+ },
293
+ {
294
+ id: 8,
295
+ username: "sophia_m",
296
+ email: "sophia.m@gmail.com",
297
+ password: "Sophi@2024",
298
+ },
299
+ {
300
+ id: 9,
301
+ username: "chrisw",
302
+ email: "chrisw@outlook.com",
303
+ password: "Chri$Wong21",
304
+ },
305
+ {
306
+ id: 10,
307
+ username: "natalie_b",
308
+ email: "natalie_b@gmail.com",
309
+ password: "N@talie#B2024",
310
+ },
311
+ ];
155
312
 
156
313
  function exceedHandler() {
157
- throw new Error("Too much call in allowed window");
314
+ const message = "Too much call in allowed window";
315
+ throw new ResponseError(message, 429);
158
316
  }
159
317
 
160
- function errorHandler(e: Error): void {
161
- console.error(e);
318
+ function getUserErrorHandler(e: Error) {
319
+ const message = "User not found.";
320
+ throw new ResponseError(message, 404, e.message);
162
321
  }
163
322
 
323
+ /**
324
+ * Controller for handling user-related operations
325
+ * @class UserController
326
+ * @desc Provides methods for user management including CRUD operations
327
+ */
164
328
  export default class UserController {
165
- //constructor(private readonly userService: UserService) { }
329
+ // constructor(private readonly userService: UserService) { }
166
330
 
167
- // Throttle the createUser method to 1 request per 200 milliseconds
168
331
  @rateLimit({
169
- timeSpanMs: 60000,
170
- allowedCalls: 300,
332
+ timeSpanMs: config.rateLimitTimeSpan,
333
+ allowedCalls: config.rateLimitAllowedCalls,
171
334
  exceedHandler,
172
335
  })
336
+ @Validate
337
+ /**
338
+ * Create a new user
339
+ * @param {UserCreationDto} user - User creation data validated by Zod schema
340
+ * @returns {Promise<void>}
341
+ * @throws {ResponseError} 500 - When rate limit exceeded
342
+ * @throws {ResponseError} 400 - Invalid input data
343
+ */
344
+ public async create(@ZodInput(ZodUserCreationDto) user: UserCreationDto) {
345
+ users.push({ ...user, id: users.length + 1 });
346
+ }
347
+
348
+ @memoizeAsync(config.memoizeTime)
173
349
  @onError({
174
- func: errorHandler,
350
+ func: getUserErrorHandler,
175
351
  })
176
- @Validate
177
- public async createUser(
178
- @ZodInput(CreateUserDto) data: CreateUser
179
- ): Promise<string> {
180
- // Here you can include logic to save user to database
181
- console.log("Creating user:", data);
182
- return "User created successfully";
352
+ @rateLimit({
353
+ timeSpanMs: config.rateLimitTimeSpan,
354
+ allowedCalls: config.rateLimitAllowedCalls,
355
+ exceedHandler,
356
+ })
357
+ /**
358
+ * Get user by ID
359
+ * @param {string} id - User ID as string
360
+ * @returns {Promise<User>} User details or error object
361
+ * @throws {ResponseError} 404 - User not found
362
+ * @throws {ResponseError} 400 - Invalid ID format
363
+ */
364
+ public async get(id: string): Promise<UserDto> {
365
+ const response = parseId(id);
366
+ const user = users.find((user) => user.id === response);
367
+ if (user == null) throw new ResponseError("User dose not exist.", 404);
368
+ return user satisfies User;
369
+ }
370
+
371
+ @memoizeAsync(config.memoizeTime)
372
+ @timeout(config.timeout)
373
+ @rateLimit({
374
+ timeSpanMs: config.rateLimitTimeSpan,
375
+ allowedCalls: config.rateLimitAllowedCalls,
376
+ exceedHandler,
377
+ })
378
+ /**
379
+ * Get all users with masked passwords
380
+ * @returns {Promise<UserDto[]>} List of users with hidden password fields
381
+ * @throws {ResponseError} 500 - When rate limit exceeded
382
+ */
383
+ public async getAll(): Promise<UserDto[]> {
384
+ return users.map((user) => ({
385
+ ...user,
386
+ password: "?",
387
+ }));
183
388
  }
184
389
  }
185
390
  ```
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "codeweaver",
3
- "version": "1.0.15",
4
- "main": "src/app.ts",
3
+ "version": "2.0.0",
4
+ "main": "src/main.ts",
5
5
  "bin": {
6
6
  "create-codeweaver-app": "./command.js"
7
7
  },
8
8
  "scripts": {
9
- "start": "nodemon src/app.ts",
10
- "build": "tsc",
11
- "serve": "node dist/app.js"
9
+ "start": "nodemon -r tsconfig-paths/register src/main.ts",
10
+ "dev": "nodemon -r tsconfig-paths/register src/main.ts",
11
+ "build": "tsc && tsc-alias && copyfiles -u 1 \"src/**/*.{json,env,sqlite,db,sql,yaml,yml,xml,txt,md}\" dist",
12
+ "serve": "cross-env TSCONFIG_PATH=tsconfig.paths.json node -r tsconfig-paths/register dist/main.js"
12
13
  },
13
14
  "keywords": [
14
15
  "codeweaver",
@@ -27,23 +28,28 @@
27
28
  "swagger",
28
29
  "zod"
29
30
  ],
30
- "author": "Ehsan Afzali",
31
+ "author": "js-code-crafter",
31
32
  "license": "MIT",
32
33
  "description": "A lightweight framework built on top of Express and TypeScript",
33
34
  "dependencies": {
34
- "express": "^4.21.1",
35
+ "dotenv": "^17.2.3",
36
+ "express": "^5.1.0",
35
37
  "express-async-handler": "^1.2.0",
36
- "ts-zod-decorators": "^1.7.1",
37
- "utils-decorators": "^2.0.9",
38
- "zod": "^3.23.8"
38
+ "swagger-jsdoc": "^3.7.0",
39
+ "ts-zod4-decorators": "^1.0.0",
40
+ "utils-decorators": "^2.10.0",
41
+ "zod": "^4.0.14"
39
42
  },
40
43
  "devDependencies": {
41
- "@types/express": "^5.0.0",
42
- "@types/node": "^22.10.7",
43
- "nodemon": "^3.1.7",
44
- "swagger-jsdoc": "^6.2.8",
44
+ "@types/express": "^5.0.3",
45
+ "@types/node": "^24.1.0",
46
+ "copyfiles": "^2.4.1",
47
+ "cross-env": "^10.0.0",
48
+ "nodemon": "^3.1.10",
45
49
  "swagger-ui-express": "^5.0.1",
46
50
  "ts-node": "^10.9.2",
47
- "typescript": "^5.6.3"
51
+ "tsc-alias": "^1.8.16",
52
+ "tsconfig-paths": "^4.2.0",
53
+ "typescript": "^5.9.2"
48
54
  }
49
55
  }
package/src/config.ts CHANGED
@@ -1,32 +1,79 @@
1
+ import {
2
+ memoizeTime,
3
+ productionEnvironment,
4
+ rateLimitTimeSpan,
5
+ rateLimitAllowedCalls,
6
+ timeout,
7
+ portNumber,
8
+ } from "./constants";
9
+
10
+ /**
11
+ * Server configuration interface
12
+ * @interface
13
+ * @property {string} url - Base server URL
14
+ */
1
15
  interface Server {
2
16
  url: string;
3
17
  }
4
18
 
19
+ /**
20
+ * API information structure
21
+ * @interface
22
+ * @property {string} title - API title
23
+ * @property {string} version - API version
24
+ * @property {string} description - API description
25
+ */
5
26
  interface Info {
6
27
  title: string;
7
28
  version: string;
8
29
  description: string;
9
30
  }
10
31
 
32
+ /**
33
+ * Swagger definition structure
34
+ * @interface
35
+ * @property {string} openApi - OpenAPI specification version
36
+ * @property {Info} info - API information
37
+ * @property {Server[]} servers - List of server configurations
38
+ */
11
39
  interface SwaggerDefinition {
12
40
  openApi: string;
13
41
  info: Info;
14
42
  servers: Server[];
15
43
  }
16
44
 
45
+ /**
46
+ * Swagger configuration options
47
+ * @interface
48
+ * @property {SwaggerDefinition} swaggerDefinition - Swagger definition object
49
+ * @property {string[]} apis - Paths to API documentation files
50
+ */
17
51
  interface SwaggerOptions {
18
52
  swaggerDefinition: SwaggerDefinition;
19
53
  apis: string[];
20
54
  }
21
55
 
56
+ /**
57
+ * Main application configuration
58
+ * @interface
59
+ * @property {boolean} devMode - Development mode flag
60
+ * @property {string} port - Server port
61
+ * @property {SwaggerOptions} swaggerOptions - Swagger configuration
62
+ */
22
63
  interface Config {
23
64
  devMode: boolean;
24
- port: string;
65
+ port: number;
25
66
  swaggerOptions: SwaggerOptions;
67
+ timeout: number;
68
+ rateLimitTimeSpan: number;
69
+ rateLimitAllowedCalls: number;
70
+ memoizeTime: number;
26
71
  }
27
- const port = process.env.PORT || "3000";
28
- const config: Config = {
29
- devMode: process.env.NODE_ENV !== "production",
72
+
73
+ const port = Number(process.env.PORT) || portNumber;
74
+
75
+ let config: Config = {
76
+ devMode: process.env.NODE_ENV !== productionEnvironment,
30
77
  port,
31
78
  swaggerOptions: {
32
79
  swaggerDefinition: {
@@ -49,17 +96,11 @@ const config: Config = {
49
96
  "./src/routers/**/*.js",
50
97
  ], // Path to the API docs
51
98
  },
99
+ timeout: Number(process.env.TIMEOUT) || timeout,
100
+ rateLimitTimeSpan: Number(process.env.RATE_LIMIT) || rateLimitTimeSpan,
101
+ rateLimitAllowedCalls:
102
+ Number(process.env.RATE_LIMIT) || rateLimitAllowedCalls,
103
+ memoizeTime: Number(process.env.MEMOIZE_TIME) || memoizeTime,
52
104
  };
53
105
 
54
- // Other configurations:
55
- //
56
- // config.jwt_key = config.devMode ? "" : "";
57
- // config.jwt_expiration = config.devMode ? 360000 : 360000;
58
- // config.dbConnectionString = config.devMode ? `mongoDb url` : `mongoDb url`;
59
- // config.mongoDebug = config.devMode;
60
- // config.port = config.devMode ? 3000 : 3000;
61
- // config.host = config.devMode ? "localhost" : "localhost";
62
- // config.env = config.devMode ? "development" : "production";
63
- // config.mongoUrl = config.devMode ? "mongodb://localhost:27017/test" : "mongodb://localhost:27017/test";
64
-
65
106
  export default config;
@@ -0,0 +1,6 @@
1
+ export const timeout = 20000;
2
+ export const rateLimitTimeSpan = 60000;
3
+ export const rateLimitAllowedCalls = 300;
4
+ export const memoizeTime = 1000 * 60 * 60;
5
+ export const productionEnvironment = "production";
6
+ export const portNumber = 3000;
package/src/main.ts ADDED
@@ -0,0 +1,82 @@
1
+ import express, { NextFunction, Request, Response } from "express";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import config from "./config";
5
+
6
+ /**
7
+ * Recursively loads Express routers from directory
8
+ * @param {string} routerPath - Directory path to scan
9
+ * @param {string} [basePath=""] - Base route path
10
+ */
11
+ function loadRouters(routerPath: string, basePath: string = "") {
12
+ // Read entries with their type info
13
+ const entries = fs.readdirSync(routerPath, { withFileTypes: true });
14
+
15
+ for (const entry of entries) {
16
+ const fullPath = path.join(routerPath, entry.name);
17
+
18
+ if (entry.isDirectory()) {
19
+ // Recurse into subdirectories
20
+ const subRoutePath = path
21
+ .join(basePath, entry.name)
22
+ .replace(/\\/g, "/")
23
+ .replace(/\/?index$/g, "");
24
+ loadRouters(fullPath, subRoutePath);
25
+ continue;
26
+ }
27
+
28
+ // Only handle router files
29
+ if (
30
+ !entry.name.endsWith(".router.ts") &&
31
+ !entry.name.endsWith(".router.js")
32
+ ) {
33
+ continue;
34
+ }
35
+
36
+ // Build route path safely
37
+ const routePath = path
38
+ .join(basePath, entry.name.replace(/\.router\.[tj]s$/, ""))
39
+ .replace(/\\/g, "/")
40
+ .replace(/\/?index$/g, "");
41
+
42
+ // Optional: skip if the target path would be empty (maps to /)
43
+ const mountPath = "/" + (routePath || "");
44
+
45
+ // Import and mount
46
+ const router = require(fullPath);
47
+ app.use(mountPath, router);
48
+ console.log(`Mounted ${entry.name} at ${mountPath}`);
49
+ }
50
+ }
51
+
52
+ const app = express();
53
+ app.use(express.json());
54
+ app.use(express.urlencoded({ extended: true }));
55
+
56
+ //app.use(cors());
57
+
58
+ // Automatically import all routers from the /src/routers directory
59
+ const routersPath = path.join(__dirname, "/routers");
60
+ loadRouters(routersPath);
61
+
62
+ // Swagger setup
63
+ if (config.devMode) {
64
+ const swaggerJsDoc = require("swagger-jsdoc");
65
+ const swaggerUi = require("swagger-ui-express");
66
+ const swaggerDocs = swaggerJsDoc(config.swaggerOptions);
67
+ app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
68
+ }
69
+
70
+ // General error handler
71
+ app.use((err: unknown, req: Request, res: Response, next: NextFunction) => {
72
+ res.status(500).json(err);
73
+ });
74
+
75
+ // Start the server
76
+ app.listen(config.port, () => {
77
+ console.log(`Server is running on http://localhost:${config.port}`);
78
+ if (config.devMode)
79
+ console.log(
80
+ `Swagger UI is available at http://localhost:${config.port}/api-docs`
81
+ );
82
+ });
@@ -11,12 +11,12 @@ const router = Router();
11
11
  * description: Returns the home page.
12
12
  * responses:
13
13
  * 200:
14
- * description: home page
14
+ * description: Hi there!
15
15
  */
16
16
  router.get(
17
17
  "/",
18
18
  asyncHandler(async (req: Request, res: Response) => {
19
- res.send("Home");
19
+ res.send("Hi there!");
20
20
  })
21
21
  );
22
22