express-ts-api-starter 1.2.0 → 1.3.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.
Files changed (39) hide show
  1. package/.env.example +23 -0
  2. package/.gitignore +136 -0
  3. package/README.md +46 -17
  4. package/bin/cli.mjs +199 -0
  5. package/eslint.config.js +22 -0
  6. package/jest.config.ts +9 -0
  7. package/package.json +12 -1
  8. package/scripts/eslint-report.js +65 -0
  9. package/src/app.ts +56 -0
  10. package/src/config/dbConfig.ts +17 -0
  11. package/src/config/emailConfig.ts +0 -0
  12. package/src/config/envConfig.ts +18 -0
  13. package/src/config/rateLimitConfig.ts +7 -0
  14. package/src/config/throttleConfig.cjs +6 -0
  15. package/src/constants/index.ts +5 -0
  16. package/src/interfaces/userInterface.ts +11 -0
  17. package/src/messages/index.ts +29 -0
  18. package/src/middleware/auth.ts +54 -0
  19. package/src/middleware/errorMiddleware.ts +30 -0
  20. package/src/middleware/logMiddleware.ts +31 -0
  21. package/src/middleware/requestIdMiddleware.ts +13 -0
  22. package/src/middleware/uploadMiddleware.ts +37 -0
  23. package/src/middleware/validatorMiddleware.ts +21 -0
  24. package/src/models/UserModel.ts +30 -0
  25. package/src/modules/users/tests/userController.test.ts +171 -0
  26. package/src/modules/users/userController.ts +78 -0
  27. package/src/modules/users/userMessage.ts +9 -0
  28. package/src/modules/users/userService.ts +84 -0
  29. package/src/routes/index.ts +9 -0
  30. package/src/routes/usersRoute.ts +13 -0
  31. package/src/server.ts +56 -0
  32. package/src/types/index.ts +13 -0
  33. package/src/types/roleType.ts +1 -0
  34. package/src/types/userTypes.ts +22 -0
  35. package/src/utils/authFunction.ts +15 -0
  36. package/src/utils/responseUtil.ts +42 -0
  37. package/src/validators/index.ts +1 -0
  38. package/src/validators/userValidators.ts +38 -0
  39. package/tsconfig.json +16 -0
package/.env.example ADDED
@@ -0,0 +1,23 @@
1
+ # Environment Configuration
2
+ NODE_ENV=development
3
+
4
+ # Server Configuration
5
+ PORT=5000
6
+ BASIC_API_URL=/api/v1
7
+
8
+ # Database Configuration
9
+ DB_CONNECTION=mongodb://localhost:27017/
10
+ DB_NAME=testDB
11
+
12
+ # Authentication
13
+ JWT_SECRET=your-super-secret-jwt-key-change-in-production
14
+
15
+ # Email Configuration (if using email features)
16
+ SMTP_HOST=smtp.gmail.com
17
+ SMTP_PORT=587
18
+ SMTP_USER=your-email@gmail.com
19
+ SMTP_PASSWORD=your-app-password
20
+
21
+ # Optional: Third-party APIs
22
+ # API_KEY=your-api-key
23
+ # EXTERNAL_SERVICE_URL=https://api.example.com
package/.gitignore ADDED
@@ -0,0 +1,136 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ lerna-debug.log*
8
+ .pnpm-debug.log*
9
+
10
+ # Diagnostic reports (https://nodejs.org/api/report.html)
11
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12
+
13
+ # Runtime data
14
+ pids
15
+ *.pid
16
+ *.seed
17
+ *.pid.lock
18
+
19
+ # Directory for instrumented libs generated by jscoverage/JSCover
20
+ lib-cov
21
+
22
+ # Coverage directory used by tools like istanbul
23
+ coverage
24
+ *.lcov
25
+
26
+ # nyc test coverage
27
+ .nyc_output
28
+
29
+ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30
+ .grunt
31
+
32
+ # Bower dependency directory (https://bower.io/)
33
+ bower_components
34
+
35
+ # node-waf configuration
36
+ .lock-wscript
37
+
38
+ # Compiled binary addons (https://nodejs.org/api/addons.html)
39
+ build/Release
40
+
41
+ # Dependency directories
42
+ node_modules/
43
+ jspm_packages/
44
+
45
+ # Snowpack dependency directory (https://snowpack.dev/)
46
+ web_modules/
47
+
48
+ # TypeScript cache
49
+ *.tsbuildinfo
50
+
51
+ # Optional npm cache directory
52
+ .npm
53
+
54
+ # Optional eslint cache
55
+ .eslintcache
56
+
57
+ # Optional stylelint cache
58
+ .stylelintcache
59
+
60
+ # Microbundle cache
61
+ .rpt2_cache/
62
+ .rts2_cache_cjs/
63
+ .rts2_cache_es/
64
+ .rts2_cache_umd/
65
+
66
+ # Optional REPL history
67
+ .node_repl_history
68
+
69
+ # Output of 'npm pack'
70
+ *.tgz
71
+
72
+ # Yarn Integrity file
73
+ .yarn-integrity
74
+
75
+ # dotenv environment variable files
76
+ .env
77
+ .env.development.local
78
+ .env.test.local
79
+ .env.production.local
80
+ .env.local
81
+
82
+ # parcel-bundler cache (https://parceljs.org/)
83
+ .cache
84
+ .parcel-cache
85
+
86
+ # Next.js build output
87
+ .next
88
+ out
89
+
90
+ # Nuxt.js build / generate output
91
+ .nuxt
92
+ dist
93
+
94
+ # Gatsby files
95
+ .cache/
96
+ # Comment in the public line in if your project uses Gatsby and not Next.js
97
+ # https://nextjs.org/blog/next-9-1#public-directory-support
98
+ # public
99
+
100
+ # vuepress build output
101
+ .vuepress/dist
102
+
103
+ # vuepress v2.x temp and cache directory
104
+ .temp
105
+ .cache
106
+
107
+ # vitepress build output
108
+ **/.vitepress/dist
109
+
110
+ # vitepress cache directory
111
+ **/.vitepress/cache
112
+
113
+ # Docusaurus cache and generated files
114
+ .docusaurus
115
+
116
+ # Serverless directories
117
+ .serverless/
118
+
119
+ # FuseBox cache
120
+ .fusebox/
121
+
122
+ # DynamoDB Local files
123
+ .dynamodb/
124
+
125
+ # TernJS port file
126
+ .tern-port
127
+
128
+ # Stores VSCode versions used for testing VSCode extensions
129
+ .vscode-test
130
+
131
+ # yarn v2
132
+ .yarn/cache
133
+ .yarn/unplugged
134
+ .yarn/build-state.yml
135
+ .yarn/install-state.gz
136
+ .pnp.*
package/README.md CHANGED
@@ -13,34 +13,48 @@
13
13
 
14
14
  ## 📌 Quick Demo
15
15
 
16
- ```typescript
17
- // Your API is ready with authentication, validation, and error handling out of the box!
18
- import app from 'express-ts-api-starter';
19
-
20
- // Start building your endpoints immediately
21
- app.get('/api/v1/users', (req, res) => {
22
- // Request ID automatically attached: req.headers['x-request-id']
23
- // Error handling: Global middleware catches all errors
24
- // Validation: Built-in express-validator ready
25
- res.json({ message: 'API is running!' });
26
- });
16
+ **Create a new project in seconds:**
17
+
18
+ ```bash
19
+ npx express-ts-api-starter my-api
20
+ cd my-api
21
+ npm install
22
+ npm run dev
27
23
  ```
28
24
 
25
+ Your API is ready with authentication, validation, and error handling out of the box!
26
+
29
27
  ---
30
28
 
31
29
  ## 🚀 Quick Start
32
30
 
33
- ### Install
31
+ ### Option 1: Using CLI (Recommended)
32
+
33
+ Create a new project with a single command:
34
+
35
+ ```bash
36
+ npx express-ts-api-starter my-api
37
+ ```
38
+
39
+ This will:
40
+ - ✅ Create a new project directory
41
+ - ✅ Copy all template files and folder structure
42
+ - ✅ Set up configuration files
43
+ - ✅ Create `.env` file from `.env.example`
44
+
45
+ Then:
34
46
 
35
47
  ```bash
36
- npm install express-ts-api-starter
48
+ cd my-api
49
+ npm install
50
+ npm run dev
37
51
  ```
38
52
 
39
- ### Launch Your Project
53
+ ### Option 2: Manual Installation
40
54
 
41
55
  ```bash
42
56
  # Clone the repository
43
- git clone https://github.com/nikhilpktcr/express-ts-starter.git my-api
57
+ git clone https://github.com/nikhilpktcr/express-ts-api-starter.git my-api
44
58
  cd my-api
45
59
 
46
60
  # Install dependencies
@@ -92,6 +106,20 @@ npm run dev
92
106
  | **TypeScript** | Sometimes | ✅ **100% TypeScript with strict mode** |
93
107
  | **Documentation** | Minimal | ✅ **Well-documented with examples** |
94
108
  | **Testing** | Sometimes | ✅ **Jest with test examples included** |
109
+ | **CLI Tool** | Sometimes | ✅ **Built-in CLI generator** |
110
+
111
+ ### vs. NestJS
112
+
113
+ | Feature | NestJS | express-ts-api-starter |
114
+ |---------|--------|------------------------|
115
+ | **Setup Time** | 10-15 minutes | ⚡ **2 minutes** |
116
+ | **Learning Curve** | High (new framework) | ✅ **Low (Express knowledge)** |
117
+ | **Bundle Size** | ~200KB+ | ✅ **~50KB (lightweight)** |
118
+ | **Flexibility** | Framework-driven | ✅ **High (minimal abstraction)** |
119
+ | **Request Tracking** | Manual setup | ✅ **Built-in request IDs** |
120
+ | **Security (Out of Box)** | Manual config | ✅ **Pre-configured** |
121
+
122
+ 📖 **[See detailed NestJS comparison →](COMPARISON-NESTJS.md)**
95
123
 
96
124
  ---
97
125
 
@@ -152,6 +180,7 @@ npm run dev
152
180
 
153
181
  ### Developer Experience
154
182
 
183
+ - ✅ **CLI Tool** - Generate projects with one command
155
184
  - ✅ **Hot reload** - See changes instantly
156
185
  - ✅ **TypeScript declarations** - Full IntelliSense support
157
186
  - ✅ **Pre-configured scripts** - dev, build, test, lint
@@ -349,7 +378,7 @@ Free for personal and commercial use! ✨
349
378
  ## 💬 Support
350
379
 
351
380
  - **Email**: nikhil.pk.connect@gmail.com
352
- - **GitHub Issues**: [Report bugs](https://github.com/nikhilpktcr/express-ts-starter/issues)
381
+ - **GitHub Issues**: [Report bugs](https://github.com/nikhilpktcr/express-ts-api-starter/issues)
353
382
  - **GitHub**: [@nikhilpktcr](https://github.com/nikhilpktcr)
354
383
 
355
384
  ---
@@ -381,7 +410,7 @@ If this boilerplate helps your project:
381
410
  **Ready to build?** Start your next API project in minutes:
382
411
 
383
412
  ```bash
384
- npm install express-ts-api-starter
413
+ npx express-ts-api-starter my-api
385
414
  ```
386
415
 
387
416
  **Happy coding!** 🎉
package/bin/cli.mjs ADDED
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname } from 'path';
7
+
8
+ // Get __dirname equivalent in ES modules
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+
12
+ // Colors for terminal output
13
+ const colors = {
14
+ reset: '\x1b[0m',
15
+ bright: '\x1b[1m',
16
+ green: '\x1b[32m',
17
+ yellow: '\x1b[33m',
18
+ blue: '\x1b[34m',
19
+ cyan: '\x1b[36m',
20
+ red: '\x1b[31m',
21
+ };
22
+
23
+ function log(message, color = 'reset') {
24
+ console.log(`${colors[color]}${message}${colors.reset}`);
25
+ }
26
+
27
+ function getProjectName() {
28
+ const args = process.argv.slice(2);
29
+ if (args.length > 0) {
30
+ return args[0];
31
+ }
32
+ return 'my-express-api';
33
+ }
34
+
35
+ function isValidProjectName(name) {
36
+ return /^[a-z0-9-]+$/.test(name) && name.length > 0;
37
+ }
38
+
39
+ function copyDirectory(src, dest) {
40
+ if (!fs.existsSync(src)) {
41
+ return;
42
+ }
43
+
44
+ fs.mkdirSync(dest, { recursive: true });
45
+ const entries = fs.readdirSync(src, { withFileTypes: true });
46
+
47
+ for (const entry of entries) {
48
+ const srcPath = path.join(src, entry.name);
49
+ const destPath = path.join(dest, entry.name);
50
+
51
+ if (entry.isDirectory()) {
52
+ // Skip node_modules and dist directories
53
+ if (entry.name === 'node_modules' || entry.name === 'dist') {
54
+ continue;
55
+ }
56
+ copyDirectory(srcPath, destPath);
57
+ } else {
58
+ // Skip certain files
59
+ if (
60
+ entry.name === 'package-lock.json' ||
61
+ entry.name === '.env' ||
62
+ entry.name === 'eslint-report.json'
63
+ ) {
64
+ continue;
65
+ }
66
+ fs.copyFileSync(srcPath, destPath);
67
+ }
68
+ }
69
+ }
70
+
71
+ function updatePackageJson(projectPath, projectName) {
72
+ const packageJsonPath = path.join(projectPath, 'package.json');
73
+ if (!fs.existsSync(packageJsonPath)) {
74
+ return;
75
+ }
76
+
77
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
78
+
79
+ // Update package name
80
+ packageJson.name = projectName;
81
+
82
+ // Remove bin field if it exists (not needed in generated project)
83
+ delete packageJson.bin;
84
+
85
+ // Remove prepublishOnly script
86
+ delete packageJson.scripts.prepublishOnly;
87
+
88
+ fs.writeFileSync(
89
+ packageJsonPath,
90
+ JSON.stringify(packageJson, null, 2) + '\n',
91
+ 'utf8'
92
+ );
93
+ }
94
+
95
+ function createEnvFile(projectPath) {
96
+ const envExamplePath = path.join(projectPath, '.env.example');
97
+ const envPath = path.join(projectPath, '.env');
98
+
99
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
100
+ fs.copyFileSync(envExamplePath, envPath);
101
+ log('✓ Created .env file from .env.example', 'green');
102
+ }
103
+ }
104
+
105
+ function main() {
106
+ log('\n🚀 Express TypeScript API Starter', 'bright');
107
+ log('=====================================\n', 'cyan');
108
+
109
+ const projectName = getProjectName();
110
+
111
+ if (!isValidProjectName(projectName)) {
112
+ log('❌ Error: Invalid project name!', 'red');
113
+ log(' Project name should only contain lowercase letters, numbers, and hyphens.\n', 'yellow');
114
+ process.exit(1);
115
+ }
116
+
117
+ const currentDir = process.cwd();
118
+ const projectPath = path.join(currentDir, projectName);
119
+
120
+ // Check if directory already exists
121
+ if (fs.existsSync(projectPath)) {
122
+ log(`❌ Error: Directory "${projectName}" already exists!`, 'red');
123
+ log(' Please choose a different name or remove the existing directory.\n', 'yellow');
124
+ process.exit(1);
125
+ }
126
+
127
+ log(`📦 Creating project: ${projectName}...\n`, 'blue');
128
+
129
+ try {
130
+ // Get the template directory (where this package is installed)
131
+ const templateDir = path.resolve(__dirname, '..');
132
+
133
+ // Create project directory
134
+ fs.mkdirSync(projectPath, { recursive: true });
135
+ log(`✓ Created directory: ${projectName}`, 'green');
136
+
137
+ // Copy template files
138
+ log('📋 Copying template files...', 'blue');
139
+
140
+ // Copy src directory
141
+ const srcDir = path.join(templateDir, 'src');
142
+ if (fs.existsSync(srcDir)) {
143
+ copyDirectory(srcDir, path.join(projectPath, 'src'));
144
+ log(' ✓ Copied src/ directory', 'green');
145
+ }
146
+
147
+ // Copy scripts directory
148
+ const scriptsDir = path.join(templateDir, 'scripts');
149
+ if (fs.existsSync(scriptsDir)) {
150
+ copyDirectory(scriptsDir, path.join(projectPath, 'scripts'));
151
+ log(' ✓ Copied scripts/ directory', 'green');
152
+ }
153
+
154
+ // Copy configuration files
155
+ const configFiles = [
156
+ 'tsconfig.json',
157
+ 'eslint.config.js',
158
+ 'jest.config.ts',
159
+ '.env.example',
160
+ '.gitignore',
161
+ 'README.md',
162
+ 'LICENSE',
163
+ ];
164
+
165
+ for (const file of configFiles) {
166
+ const srcFile = path.join(templateDir, file);
167
+ if (fs.existsSync(srcFile)) {
168
+ fs.copyFileSync(srcFile, path.join(projectPath, file));
169
+ log(` ✓ Copied ${file}`, 'green');
170
+ }
171
+ }
172
+
173
+ // Update package.json
174
+ updatePackageJson(projectPath, projectName);
175
+ log(' ✓ Updated package.json', 'green');
176
+
177
+ // Create .env file
178
+ createEnvFile(projectPath);
179
+
180
+ log('\n✅ Project created successfully!\n', 'green');
181
+
182
+ // Next steps
183
+ log('📝 Next steps:', 'bright');
184
+ log(` cd ${projectName}`, 'cyan');
185
+ log(' npm install', 'cyan');
186
+ log(' npm run dev', 'cyan');
187
+ log('\n🎉 Happy coding!\n', 'green');
188
+
189
+ } catch (error) {
190
+ log(`\n❌ Error: ${error.message}`, 'red');
191
+ // Clean up on error
192
+ if (fs.existsSync(projectPath)) {
193
+ fs.rmSync(projectPath, { recursive: true, force: true });
194
+ }
195
+ process.exit(1);
196
+ }
197
+ }
198
+
199
+ main();
@@ -0,0 +1,22 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import tseslint from 'typescript-eslint'
4
+
5
+ export default tseslint.config({
6
+ ignores: ['dist/**'],
7
+ },
8
+ {
9
+ extends: [
10
+ js.configs.recommended,
11
+ ...tseslint.configs.recommended,
12
+ ],
13
+ files: ['**/*.{ts,js,cjs,mjs}'],
14
+ languageOptions: {
15
+ ecmaVersion: 2020,
16
+ globals: globals.browser,
17
+ },
18
+ rules: {
19
+ '@typescript-eslint/no-unused-vars': 'off',
20
+ '@typescript-eslint/no-explicit-any': "off"
21
+ },
22
+ });
package/jest.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { Config } from 'jest';
2
+
3
+ const config: Config = {
4
+ preset: 'ts-jest',
5
+ testEnvironment: 'node',
6
+ testPathIgnorePatterns: ['/dist/'],
7
+ };
8
+
9
+ export default config;
package/package.json CHANGED
@@ -1,13 +1,24 @@
1
1
  {
2
2
  "name": "express-ts-api-starter",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Production-ready Express.js + TypeScript boilerplate with MVC architecture, JWT auth, MongoDB, security, validation, and testing—build scalable REST APIs fast",
5
5
  "main": "dist/server.js",
6
6
  "types": "dist/server.d.ts",
7
+ "bin": {
8
+ "express-ts-api-starter": "./bin/cli.mjs"
9
+ },
7
10
  "files": [
11
+ "src",
8
12
  "dist",
9
13
  "!dist/**/*.test.js",
10
14
  "!dist/**/*.spec.js",
15
+ "scripts",
16
+ "bin",
17
+ "tsconfig.json",
18
+ "eslint.config.js",
19
+ "jest.config.ts",
20
+ ".env.example",
21
+ ".gitignore",
11
22
  "README.md",
12
23
  "LICENSE"
13
24
  ],
@@ -0,0 +1,65 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import { execSync } from 'child_process';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ // Emulate __dirname in ES modules
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ const reportPath = path.resolve(process.cwd(), 'eslint-report.json');
12
+
13
+ // Step 1: Run ESLint and generate report
14
+ try {
15
+ console.log(chalk.blue('🔍 Running ESLint...'));
16
+ execSync('npx eslint . --ext .ts,.js --format json -o eslint-report.json', { stdio: 'inherit' });
17
+ } catch (err) {
18
+ console.error(chalk.red('❌ ESLint execution failed.'));
19
+ process.exit(1);
20
+ }
21
+
22
+ // Step 2: Read and display the report
23
+ if (!fs.existsSync(reportPath)) {
24
+ console.error(chalk.red('❌ ESLint report not found.'));
25
+ process.exit(1);
26
+ }
27
+
28
+ const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
29
+
30
+ let totalErrors = 0;
31
+ let totalWarnings = 0;
32
+ let passedFiles = 0;
33
+
34
+ console.log(chalk.bold('\nTest Suites: ESLint Report\n'));
35
+
36
+ report.forEach((file) => {
37
+ const fileName = path.relative(process.cwd(), file.filePath);
38
+ const errors = file.errorCount;
39
+ const warnings = file.warningCount;
40
+
41
+ totalErrors += errors;
42
+ totalWarnings += warnings;
43
+
44
+ if (errors === 0 && warnings === 0) {
45
+ passedFiles++;
46
+ console.log(chalk.green(`✓ ${fileName}`));
47
+ } else {
48
+ console.log(chalk.red(`✖ ${fileName}`));
49
+ file.messages.forEach((msg) => {
50
+ const severity = msg.severity === 2 ? chalk.red('error') : chalk.yellow('warning');
51
+ console.log(` ${chalk.gray(msg.ruleId || 'unknown')} - ${severity}: ${msg.message}`);
52
+ });
53
+ }
54
+ });
55
+
56
+ console.log('\n' + chalk.bold('Summary:'));
57
+ console.log(chalk.green(` Passed files: ${passedFiles}/${report.length}`));
58
+ console.log(chalk.red(` Total Errors: ${totalErrors}`));
59
+ console.log(chalk.yellow(` Total Warnings: ${totalWarnings}\n`));
60
+
61
+ if (totalErrors === 0) {
62
+ console.log(chalk.green.bold('✔ All files passed linting!\n'));
63
+ } else {
64
+ console.log(chalk.red.bold('✖ Linting issues detected.\n'));
65
+ }
package/src/app.ts ADDED
@@ -0,0 +1,56 @@
1
+ import express, { Application, Request } from "express";
2
+ import cors from "cors";
3
+ import morgan from "morgan";
4
+ import { env } from "./config/envConfig";
5
+ import routes from "./routes";
6
+ import helmet from "helmet";
7
+ // import { limiterConfig } from "./config/rateLimitConfig";
8
+ import connectDB from "./config/dbConfig";
9
+ import {
10
+ globalErrorHandler,
11
+ notFoundHandler,
12
+ } from "./middleware/errorMiddleware";
13
+ import { sendErrorResponse } from "./utils/responseUtil";
14
+ import { StatusCodes } from "http-status-codes";
15
+ import { requestIdMiddleware } from "./middleware/requestIdMiddleware";
16
+
17
+ const app: Application = express();
18
+
19
+ // ===== Middleware =====
20
+ // app.use(limiterConfig);
21
+ app.use(helmet());
22
+ app.use(cors());
23
+ app.use(express.json());
24
+ app.use(express.urlencoded({ extended: true }));
25
+ connectDB();
26
+
27
+ // ===== Request ID Middleware =====
28
+ app.use(requestIdMiddleware);
29
+
30
+ // ===== Morgan Logging with Request ID =====
31
+
32
+ morgan.token("id", (req: Request) => {
33
+ const requestId = req.headers["x-request-id"];
34
+ return typeof requestId === "string"
35
+ ? requestId
36
+ : Array.isArray(requestId)
37
+ ? requestId[0]
38
+ : "unknown";
39
+ });
40
+
41
+ app.use(
42
+ morgan(
43
+ "🧾 requestId=:id 🚀 :method :url 📦 status=:status ⏱️ :response-time ms"
44
+ )
45
+ );
46
+
47
+ // ===== API Routes =====
48
+ app.use(env.BASIC_API_URL, routes);
49
+
50
+ // ===== Un handled Routes =====
51
+ app.use(notFoundHandler);
52
+
53
+ // ===== Global Error Handler =====
54
+ app.use(globalErrorHandler);
55
+
56
+ export default app;
@@ -0,0 +1,17 @@
1
+ import mongoose from "mongoose";
2
+ import { env } from "./envConfig";
3
+ import messages from "../messages";
4
+
5
+ const connectDB = async (): Promise<void> => {
6
+ try {
7
+ await mongoose.connect(env.DB_CONNECTION, {
8
+ dbName: env.DB_NAME,
9
+ });
10
+ console.log(`${env.DB_NAME} ${messages.DB_CONNECT_SUCESS}`);
11
+ } catch (error) {
12
+ console.error(`${env.DB_NAME} ${messages.DB_CONNECT_FAILED}`, error);
13
+ process.exit(1);
14
+ }
15
+ };
16
+
17
+ export default connectDB;
File without changes
@@ -0,0 +1,18 @@
1
+ import dotenv from "dotenv";
2
+ dotenv.config();
3
+
4
+ function getEnvVar(key: string, fallback?: string): string {
5
+ const value = process.env[key];
6
+ if (!value && fallback === undefined) {
7
+ throw new Error(`Missing required environment variable: ${key}`);
8
+ }
9
+ return value || fallback!;
10
+ }
11
+
12
+ export const env = {
13
+ PORT: getEnvVar("PORT", "5000"),
14
+ BASIC_API_URL: getEnvVar("BASIC_API_URL", "/api/v1"),
15
+ DB_NAME: getEnvVar("DB_NAME", "testDB"),
16
+ JWT_SECRET: getEnvVar("JWT_SECRET", "supersecret"),
17
+ DB_CONNECTION: getEnvVar("DB_CONNECTION", "mongodb://localhost:27017/"),
18
+ };
@@ -0,0 +1,7 @@
1
+ import { rateLimit } from "express-rate-limit";
2
+
3
+ export const limiterConfig = rateLimit({
4
+ windowMs: 15 * 60 * 1000, // 15 minutes
5
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
6
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
7
+ });