create-express-mongoose-app 1.0.0 → 1.0.2
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.
- package/README.md +5 -5
- package/package.json +2 -1
- package/my-test/.env.example +0 -21
- package/my-test/README.md +0 -137
- package/my-test/package.json +0 -38
- package/my-test/src/app.ts +0 -77
- package/my-test/src/config/database.ts +0 -54
- package/my-test/src/config/env.ts +0 -42
- package/my-test/src/config/winston-logger.ts +0 -75
- package/my-test/src/index.ts +0 -3
- package/my-test/src/middleware/error.middleware.ts +0 -88
- package/my-test/src/middleware/request-id.middleware.ts +0 -20
- package/my-test/src/modules/example/example.controller.ts +0 -45
- package/my-test/src/modules/example/example.model.ts +0 -31
- package/my-test/src/modules/example/example.route.ts +0 -20
- package/my-test/src/modules/example/example.service.ts +0 -92
- package/my-test/src/modules/example/example.validation.ts +0 -16
- package/my-test/src/server.ts +0 -57
- package/my-test/src/utils/apiError.ts +0 -63
- package/my-test/src/utils/asyncHandler.ts +0 -7
- package/my-test/src/utils/response.ts +0 -102
- package/my-test/src/utils/validationMiddleware.ts +0 -32
- package/my-test/tsconfig.json +0 -26
- package/my-test/yarn.lock +0 -1149
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# create-express-
|
|
1
|
+
# create-express-mongoose-app
|
|
2
2
|
|
|
3
3
|
A CLI tool to quickly bootstrap a production-grade Express.js + MongoDB/Mongoose project with TypeScript.
|
|
4
4
|
|
|
@@ -17,13 +17,13 @@ A CLI tool to quickly bootstrap a production-grade Express.js + MongoDB/Mongoose
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install -g create-express-
|
|
20
|
+
npm install -g create-express-mongoose-app
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Or use npx without installation:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx create-express-
|
|
26
|
+
npx create-express-mongoose-app
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## Usage
|
|
@@ -31,13 +31,13 @@ npx create-express-mongo-app
|
|
|
31
31
|
Run the CLI:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
create-express-
|
|
34
|
+
create-express-mongoose-app
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Or with npx:
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
npx create-express-
|
|
40
|
+
npx create-express-mongoose-app
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
The CLI will ask for:
|
package/package.json
CHANGED
package/my-test/.env.example
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Server Configuration
|
|
2
|
-
NODE_ENV=development
|
|
3
|
-
PORT=3000
|
|
4
|
-
API_PREFIX=/api
|
|
5
|
-
|
|
6
|
-
# Database Configuration
|
|
7
|
-
MONGODB_URI=mongodb://localhost:27017/express-mongo-starter
|
|
8
|
-
DB_MIN_POOL_SIZE=5
|
|
9
|
-
DB_MAX_POOL_SIZE=10
|
|
10
|
-
|
|
11
|
-
# Logging Configuration
|
|
12
|
-
LOG_LEVEL=info
|
|
13
|
-
ENABLE_FILE_LOGGING=false
|
|
14
|
-
|
|
15
|
-
# Security & Rate Limiting
|
|
16
|
-
CORS_ORIGIN=http://localhost:3000
|
|
17
|
-
RATE_LIMIT_WINDOW_MS=900000
|
|
18
|
-
RATE_LIMIT_MAX_REQUESTS=100
|
|
19
|
-
|
|
20
|
-
# Request Configuration
|
|
21
|
-
REQUEST_BODY_LIMIT=10kb
|
package/my-test/README.md
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# Express MongoDB Starter Template
|
|
2
|
-
|
|
3
|
-
A production-grade Express.js + MongoDB/Mongoose starter template with TypeScript, comprehensive error handling, Winston logging, Joi validation, and security best practices.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- ✅ **TypeScript** - Strict mode enabled
|
|
8
|
-
- ✅ **Error Handling** - Centralized error middleware with standardized responses
|
|
9
|
-
- ✅ **Response Handler** - Universal ApiResponseHandler with error/success/info methods
|
|
10
|
-
- ✅ **Logging** - Winston logger with file rotation
|
|
11
|
-
- ✅ **Validation** - Joi schema validation
|
|
12
|
-
- ✅ **Security** - Helmet, CORS, Rate Limiting
|
|
13
|
-
- ✅ **Database** - MongoDB with connection retry logic and graceful shutdown
|
|
14
|
-
- ✅ **Async Handler** - Eliminate try-catch boilerplate
|
|
15
|
-
- ✅ **Health Checks** - /health and /ready endpoints
|
|
16
|
-
|
|
17
|
-
## Quick Start
|
|
18
|
-
|
|
19
|
-
1. Clone this repository
|
|
20
|
-
2. Install dependencies:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm install
|
|
24
|
-
# or
|
|
25
|
-
yarn install
|
|
26
|
-
# or
|
|
27
|
-
pnpm install
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
3. Copy `.env.example` to `.env` and configure:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
cp .env.example .env
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
4. Start development server:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm run dev
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
5. Build for production:
|
|
43
|
-
```bash
|
|
44
|
-
npm run build
|
|
45
|
-
npm start
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Project Structure
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
src/
|
|
52
|
-
├── config/ # Configuration files
|
|
53
|
-
│ ├── env.ts # Environment variables
|
|
54
|
-
│ ├── database.ts # MongoDB connection
|
|
55
|
-
│ └── winston-logger.ts # Logger setup
|
|
56
|
-
├── middleware/ # Express middleware
|
|
57
|
-
│ ├── error.middleware.ts
|
|
58
|
-
│ ├── auth.middleware.ts
|
|
59
|
-
│ └── request-id.middleware.ts
|
|
60
|
-
├── modules/ # Feature modules
|
|
61
|
-
│ └── example/ # Example module
|
|
62
|
-
│ ├── example.controller.ts
|
|
63
|
-
│ ├── example.service.ts
|
|
64
|
-
│ ├── example.model.ts
|
|
65
|
-
│ ├── example.route.ts
|
|
66
|
-
│ └── example.validation.ts
|
|
67
|
-
├── utils/ # Utility functions
|
|
68
|
-
│ ├── response.ts # Response handler
|
|
69
|
-
│ ├── asyncHandler.ts
|
|
70
|
-
│ ├── apiError.ts
|
|
71
|
-
│ └── validationMiddleware.ts
|
|
72
|
-
├── app.ts # Express app setup
|
|
73
|
-
├── index.ts # Entry point
|
|
74
|
-
└── generate-module.ts # Module generator CLI
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## API Response Format
|
|
78
|
-
|
|
79
|
-
All endpoints return standardized responses:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
// Success Response
|
|
83
|
-
{
|
|
84
|
-
"status": "success",
|
|
85
|
-
"data": {...},
|
|
86
|
-
"message": "Retrieved successfully"
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Error Response
|
|
90
|
-
{
|
|
91
|
-
"status": "error",
|
|
92
|
-
"message": "Error message",
|
|
93
|
-
"errors": {...},
|
|
94
|
-
"statusCode": 400
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Info Response
|
|
98
|
-
{
|
|
99
|
-
"status": "info",
|
|
100
|
-
"message": "Info message",
|
|
101
|
-
"data": {...}
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Generating New Modules
|
|
106
|
-
|
|
107
|
-
Generate a new module with all CRUD operations:
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
npm run generate-module <module-name>
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
This creates:
|
|
114
|
-
|
|
115
|
-
- Controller
|
|
116
|
-
- Service
|
|
117
|
-
- Model
|
|
118
|
-
- Routes
|
|
119
|
-
- Validation schema
|
|
120
|
-
|
|
121
|
-
## Environment Variables
|
|
122
|
-
|
|
123
|
-
See `.env.example` for all available configuration options.
|
|
124
|
-
|
|
125
|
-
## Error Handling
|
|
126
|
-
|
|
127
|
-
Errors are automatically caught by the centralized error middleware and formatted consistently. Supports:
|
|
128
|
-
|
|
129
|
-
- Mongoose validation errors
|
|
130
|
-
- MongoDB duplicate key errors (11000)
|
|
131
|
-
- JWT errors
|
|
132
|
-
- Custom ApiError instances
|
|
133
|
-
- Unhandled exceptions
|
|
134
|
-
|
|
135
|
-
## License
|
|
136
|
-
|
|
137
|
-
MIT
|
package/my-test/package.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "express-mongo-starter",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "Production-grade Express.js with MongoDB/Mongoose starter template",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "ts-node src/index.ts",
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"start": "node dist/index.js",
|
|
10
|
-
"generate-module": "ts-node src/generate-module.ts"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"cors": "^2.8.5",
|
|
14
|
-
"dotenv": "^16.3.1",
|
|
15
|
-
"express": "^4.18.2",
|
|
16
|
-
"express-async-errors": "^3.1.1",
|
|
17
|
-
"express-rate-limit": "^7.1.5",
|
|
18
|
-
"express-validator": "^7.0.0",
|
|
19
|
-
"helmet": "^7.1.0",
|
|
20
|
-
"http-status-codes": "^2.3.0",
|
|
21
|
-
"joi": "^17.11.0",
|
|
22
|
-
"mongoose": "^8.1.0",
|
|
23
|
-
"morgan": "^1.10.0",
|
|
24
|
-
"uuid": "^13.0.0",
|
|
25
|
-
"winston": "^3.11.0"
|
|
26
|
-
},
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"@types/cors": "^2.8.19",
|
|
29
|
-
"@types/express": "^4.17.21",
|
|
30
|
-
"@types/morgan": "^1.9.10",
|
|
31
|
-
"@types/node": "^20.10.6",
|
|
32
|
-
"ts-node": "^10.9.2",
|
|
33
|
-
"typescript": "^5.3.3"
|
|
34
|
-
},
|
|
35
|
-
"engines": {
|
|
36
|
-
"node": ">=16.0.0"
|
|
37
|
-
}
|
|
38
|
-
}
|
package/my-test/src/app.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import express, { Express, Request, Response } from "express";
|
|
2
|
-
import helmet from "helmet";
|
|
3
|
-
import cors from "cors";
|
|
4
|
-
import rateLimit from "express-rate-limit";
|
|
5
|
-
import morgan from "morgan";
|
|
6
|
-
import "express-async-errors";
|
|
7
|
-
import { config } from "./config/env";
|
|
8
|
-
import { errorMiddleware } from "./middleware/error.middleware";
|
|
9
|
-
import { requestIdMiddleware } from "./middleware/request-id.middleware";
|
|
10
|
-
import { logger } from "./config/winston-logger";
|
|
11
|
-
import { ApiResponseHandler } from "./utils/response";
|
|
12
|
-
|
|
13
|
-
export const createApp = (): Express => {
|
|
14
|
-
const app = express();
|
|
15
|
-
|
|
16
|
-
// Security middleware
|
|
17
|
-
app.use(helmet());
|
|
18
|
-
app.use(
|
|
19
|
-
cors({
|
|
20
|
-
origin: config.corsOrigin,
|
|
21
|
-
credentials: true,
|
|
22
|
-
}),
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// Request ID middleware
|
|
26
|
-
app.use(requestIdMiddleware);
|
|
27
|
-
|
|
28
|
-
// Body parser middleware
|
|
29
|
-
app.use(express.json({ limit: config.requestBodyLimit }));
|
|
30
|
-
app.use(
|
|
31
|
-
express.urlencoded({ limit: config.requestBodyLimit, extended: true }),
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Rate limiting
|
|
35
|
-
const limiter = rateLimit({
|
|
36
|
-
windowMs: config.rateLimitWindowMs,
|
|
37
|
-
max: config.rateLimitMaxRequests,
|
|
38
|
-
message: "Too many requests from this IP, please try again later.",
|
|
39
|
-
});
|
|
40
|
-
app.use(limiter);
|
|
41
|
-
|
|
42
|
-
// Logging middleware
|
|
43
|
-
app.use(
|
|
44
|
-
morgan("combined", {
|
|
45
|
-
stream: {
|
|
46
|
-
write: (message) => logger.info(message.trim()),
|
|
47
|
-
},
|
|
48
|
-
}),
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
// Health check endpoints
|
|
52
|
-
app.get("/health", (req: Request, res: Response) => {
|
|
53
|
-
ApiResponseHandler.success(res, { status: "healthy" }, "Server is running");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
app.get("/ready", (req: Request, res: Response) => {
|
|
57
|
-
ApiResponseHandler.success(res, { ready: true }, "Server is ready");
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// API routes
|
|
61
|
-
app.use(config.apiPrefix, (req: Request, res: Response) => {
|
|
62
|
-
ApiResponseHandler.info(res, "API is running", {
|
|
63
|
-
version: "1.0.0",
|
|
64
|
-
apiPrefix: config.apiPrefix,
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// 404 handler
|
|
69
|
-
app.use("*", (req: Request, res: Response) => {
|
|
70
|
-
ApiResponseHandler.error(res, "Route not found", 404);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Error middleware (must be last)
|
|
74
|
-
app.use(errorMiddleware);
|
|
75
|
-
|
|
76
|
-
return app;
|
|
77
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import mongoose from "mongoose";
|
|
2
|
-
import { config } from "./env";
|
|
3
|
-
import { logger } from "./winston-logger";
|
|
4
|
-
|
|
5
|
-
export const connectDatabase = async () => {
|
|
6
|
-
try {
|
|
7
|
-
const mongoOptions = {
|
|
8
|
-
minPoolSize: 5,
|
|
9
|
-
maxPoolSize: 10,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
await mongoose.connect(config.mongodbUri, mongoOptions);
|
|
13
|
-
|
|
14
|
-
logger.info("Database connected successfully");
|
|
15
|
-
|
|
16
|
-
mongoose.connection.on("disconnected", () => {
|
|
17
|
-
logger.warn("Database disconnected");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
mongoose.connection.on("error", (error) => {
|
|
21
|
-
logger.error("Database connection error:", error);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
mongoose.connection.on("reconnected", () => {
|
|
25
|
-
logger.info("Database reconnected");
|
|
26
|
-
});
|
|
27
|
-
} catch (error: any) {
|
|
28
|
-
logger.error("Failed to connect to database:", error.message);
|
|
29
|
-
// Retry logic
|
|
30
|
-
const retryAttempts = 5;
|
|
31
|
-
for (let i = 1; i <= retryAttempts; i++) {
|
|
32
|
-
logger.info(`Retrying database connection (${i}/${retryAttempts})...`);
|
|
33
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
34
|
-
try {
|
|
35
|
-
await mongoose.connect(config.mongodbUri);
|
|
36
|
-
logger.info("Database connected successfully on retry");
|
|
37
|
-
return;
|
|
38
|
-
} catch (retryError: any) {
|
|
39
|
-
logger.error(`Retry attempt ${i} failed:`, retryError.message);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const disconnectDatabase = async () => {
|
|
47
|
-
try {
|
|
48
|
-
await mongoose.disconnect();
|
|
49
|
-
logger.info("Database disconnected");
|
|
50
|
-
} catch (error: any) {
|
|
51
|
-
logger.error("Error disconnecting database:", error.message);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import dotenv from "dotenv";
|
|
2
|
-
|
|
3
|
-
dotenv.config();
|
|
4
|
-
|
|
5
|
-
export interface IConfig {
|
|
6
|
-
port: number;
|
|
7
|
-
nodeEnv: string;
|
|
8
|
-
mongodbUri: string;
|
|
9
|
-
apiPrefix: string;
|
|
10
|
-
logLevel: string;
|
|
11
|
-
corsOrigin: string;
|
|
12
|
-
rateLimitWindowMs: number;
|
|
13
|
-
rateLimitMaxRequests: number;
|
|
14
|
-
requestBodyLimit: string;
|
|
15
|
-
enableFileLogging: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const config: IConfig = {
|
|
19
|
-
port: parseInt(process.env.PORT || "3000"),
|
|
20
|
-
nodeEnv: process.env.NODE_ENV || "development",
|
|
21
|
-
mongodbUri:
|
|
22
|
-
process.env.MONGODB_URI ||
|
|
23
|
-
"mongodb://localhost:27017/express-mongo-starter",
|
|
24
|
-
apiPrefix: process.env.API_PREFIX || "/api",
|
|
25
|
-
logLevel: process.env.LOG_LEVEL || "info",
|
|
26
|
-
corsOrigin: process.env.CORS_ORIGIN || "http://localhost:3000",
|
|
27
|
-
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || "900000"),
|
|
28
|
-
rateLimitMaxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || "100"),
|
|
29
|
-
requestBodyLimit: process.env.REQUEST_BODY_LIMIT || "10kb",
|
|
30
|
-
enableFileLogging: process.env.ENABLE_FILE_LOGGING === "true",
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// Validate required environment variables in production
|
|
34
|
-
if (config.nodeEnv === "production") {
|
|
35
|
-
const requiredVars = ["MONGODB_URI"];
|
|
36
|
-
const missingVars = requiredVars.filter((v) => !process.env[v]);
|
|
37
|
-
if (missingVars.length > 0) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`Missing required environment variables: ${missingVars.join(", ")}`,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import winston from "winston";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { config } from "./env";
|
|
4
|
-
|
|
5
|
-
const logsDir = path.join(process.cwd(), "logs");
|
|
6
|
-
|
|
7
|
-
const levels = {
|
|
8
|
-
error: 0,
|
|
9
|
-
warn: 1,
|
|
10
|
-
info: 2,
|
|
11
|
-
debug: 3,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const colors = {
|
|
15
|
-
error: "red",
|
|
16
|
-
warn: "yellow",
|
|
17
|
-
info: "green",
|
|
18
|
-
debug: "blue",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
winston.addColors(colors);
|
|
22
|
-
|
|
23
|
-
const format = winston.format.combine(
|
|
24
|
-
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
25
|
-
winston.format.printf(
|
|
26
|
-
(info) =>
|
|
27
|
-
`${info.timestamp} [${info.level}]: ${info.message}${info.error ? "\n" + info.error : ""}`,
|
|
28
|
-
),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const transports: winston.transport[] = [
|
|
32
|
-
new winston.transports.Console({
|
|
33
|
-
format: winston.format.combine(
|
|
34
|
-
winston.format.colorize({ all: true }),
|
|
35
|
-
format,
|
|
36
|
-
),
|
|
37
|
-
}),
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
if (config.nodeEnv === "production" || config.enableFileLogging) {
|
|
41
|
-
transports.push(
|
|
42
|
-
new winston.transports.File({
|
|
43
|
-
filename: path.join(logsDir, "error.log"),
|
|
44
|
-
level: "error",
|
|
45
|
-
format,
|
|
46
|
-
maxsize: 5242880,
|
|
47
|
-
maxFiles: 5,
|
|
48
|
-
}),
|
|
49
|
-
new winston.transports.File({
|
|
50
|
-
filename: path.join(logsDir, "combined.log"),
|
|
51
|
-
format,
|
|
52
|
-
maxsize: 5242880,
|
|
53
|
-
maxFiles: 5,
|
|
54
|
-
}),
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const logger = winston.createLogger({
|
|
59
|
-
level: config.logLevel || "info",
|
|
60
|
-
levels,
|
|
61
|
-
format,
|
|
62
|
-
transports,
|
|
63
|
-
exceptionHandlers: [
|
|
64
|
-
new winston.transports.File({
|
|
65
|
-
filename: path.join(logsDir, "exceptions.log"),
|
|
66
|
-
}),
|
|
67
|
-
],
|
|
68
|
-
rejectionHandlers: [
|
|
69
|
-
new winston.transports.File({
|
|
70
|
-
filename: path.join(logsDir, "rejections.log"),
|
|
71
|
-
}),
|
|
72
|
-
],
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
export default logger;
|
package/my-test/src/index.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { ApiResponseHandler } from "../utils/response";
|
|
3
|
-
import { ApiError } from "../utils/apiError";
|
|
4
|
-
import { logger } from "../config/winston-logger";
|
|
5
|
-
import { StatusCodes } from "http-status-codes";
|
|
6
|
-
|
|
7
|
-
export const errorMiddleware = (
|
|
8
|
-
err: any,
|
|
9
|
-
req: Request,
|
|
10
|
-
res: Response,
|
|
11
|
-
next: NextFunction,
|
|
12
|
-
) => {
|
|
13
|
-
const requestId = req.id || "unknown";
|
|
14
|
-
|
|
15
|
-
// Handle Mongoose validation errors
|
|
16
|
-
if (err.name === "ValidationError") {
|
|
17
|
-
const errors: Record<string, any> = {};
|
|
18
|
-
Object.keys(err.errors).forEach((key) => {
|
|
19
|
-
errors[key] = err.errors[key].message;
|
|
20
|
-
});
|
|
21
|
-
logger.error(`[${requestId}] Validation Error:`, errors);
|
|
22
|
-
return ApiResponseHandler.error(
|
|
23
|
-
res,
|
|
24
|
-
"Validation failed",
|
|
25
|
-
StatusCodes.UNPROCESSABLE_ENTITY,
|
|
26
|
-
errors,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Handle Mongoose cast errors
|
|
31
|
-
if (err.name === "CastError") {
|
|
32
|
-
logger.error(`[${requestId}] Invalid ID format`);
|
|
33
|
-
return ApiResponseHandler.error(
|
|
34
|
-
res,
|
|
35
|
-
"Invalid ID format",
|
|
36
|
-
StatusCodes.BAD_REQUEST,
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Handle duplicate key errors
|
|
41
|
-
if (err.code === 11000) {
|
|
42
|
-
const field = Object.keys(err.keyPattern)[0];
|
|
43
|
-
logger.error(`[${requestId}] Duplicate key error on field: ${field}`);
|
|
44
|
-
return ApiResponseHandler.error(
|
|
45
|
-
res,
|
|
46
|
-
`${field} already exists`,
|
|
47
|
-
StatusCodes.CONFLICT,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Handle JWT errors
|
|
52
|
-
if (err.name === "JsonWebTokenError") {
|
|
53
|
-
logger.error(`[${requestId}] JWT Error: ${err.message}`);
|
|
54
|
-
return ApiResponseHandler.error(
|
|
55
|
-
res,
|
|
56
|
-
"Invalid token",
|
|
57
|
-
StatusCodes.UNAUTHORIZED,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (err.name === "TokenExpiredError") {
|
|
62
|
-
logger.error(`[${requestId}] Token Expired`);
|
|
63
|
-
return ApiResponseHandler.error(
|
|
64
|
-
res,
|
|
65
|
-
"Token expired",
|
|
66
|
-
StatusCodes.UNAUTHORIZED,
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Handle custom ApiError
|
|
71
|
-
if (err instanceof ApiError) {
|
|
72
|
-
logger.error(`[${requestId}] ApiError: ${err.message}`, err.errors);
|
|
73
|
-
return ApiResponseHandler.error(
|
|
74
|
-
res,
|
|
75
|
-
err.message,
|
|
76
|
-
err.statusCode,
|
|
77
|
-
err.errors,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Handle unexpected errors
|
|
82
|
-
logger.error(`[${requestId}] Unexpected Error:`, err.message);
|
|
83
|
-
return ApiResponseHandler.error(
|
|
84
|
-
res,
|
|
85
|
-
"Internal server error",
|
|
86
|
-
StatusCodes.INTERNAL_SERVER_ERROR,
|
|
87
|
-
);
|
|
88
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from "express";
|
|
2
|
-
import { v4 as uuidv4 } from "uuid";
|
|
3
|
-
|
|
4
|
-
declare global {
|
|
5
|
-
namespace Express {
|
|
6
|
-
interface Request {
|
|
7
|
-
id?: string;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const requestIdMiddleware = (
|
|
13
|
-
req: Request,
|
|
14
|
-
res: Response,
|
|
15
|
-
next: NextFunction,
|
|
16
|
-
) => {
|
|
17
|
-
req.id = uuidv4();
|
|
18
|
-
res.setHeader("X-Request-ID", req?.id!);
|
|
19
|
-
next();
|
|
20
|
-
};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from "express";
|
|
2
|
-
import { ExampleService } from "./example.service";
|
|
3
|
-
import { ApiResponseHandler } from "../../utils/response";
|
|
4
|
-
import { asyncHandler } from "../../utils/asyncHandler";
|
|
5
|
-
|
|
6
|
-
const exampleService = new ExampleService();
|
|
7
|
-
|
|
8
|
-
export const getAllExamples = asyncHandler(
|
|
9
|
-
async (req: Request, res: Response) => {
|
|
10
|
-
const examples = await exampleService.findAll();
|
|
11
|
-
ApiResponseHandler.success(
|
|
12
|
-
res,
|
|
13
|
-
examples,
|
|
14
|
-
"Examples retrieved successfully",
|
|
15
|
-
);
|
|
16
|
-
},
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
export const getExampleById = asyncHandler(
|
|
20
|
-
async (req: Request, res: Response) => {
|
|
21
|
-
const example = await exampleService.findById(req.params.id);
|
|
22
|
-
ApiResponseHandler.success(res, example, "Example retrieved successfully");
|
|
23
|
-
},
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
export const createExample = asyncHandler(
|
|
27
|
-
async (req: Request, res: Response) => {
|
|
28
|
-
const example = await exampleService.create(req.body);
|
|
29
|
-
ApiResponseHandler.created(res, example, "Example created successfully");
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
export const updateExample = asyncHandler(
|
|
34
|
-
async (req: Request, res: Response) => {
|
|
35
|
-
const example = await exampleService.update(req.params.id, req.body);
|
|
36
|
-
ApiResponseHandler.success(res, example, "Example updated successfully");
|
|
37
|
-
},
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
export const deleteExample = asyncHandler(
|
|
41
|
-
async (req: Request, res: Response) => {
|
|
42
|
-
await exampleService.delete(req.params.id);
|
|
43
|
-
ApiResponseHandler.noContent(res);
|
|
44
|
-
},
|
|
45
|
-
);
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import mongoose, { Schema, Document } from "mongoose";
|
|
2
|
-
|
|
3
|
-
export interface IExample extends Document {
|
|
4
|
-
name: string;
|
|
5
|
-
description?: string;
|
|
6
|
-
isActive: boolean;
|
|
7
|
-
createdAt: Date;
|
|
8
|
-
updatedAt: Date;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const ExampleSchema = new Schema(
|
|
12
|
-
{
|
|
13
|
-
name: {
|
|
14
|
-
type: String,
|
|
15
|
-
required: [true, "Name is required"],
|
|
16
|
-
trim: true,
|
|
17
|
-
unique: true,
|
|
18
|
-
},
|
|
19
|
-
description: {
|
|
20
|
-
type: String,
|
|
21
|
-
trim: true,
|
|
22
|
-
},
|
|
23
|
-
isActive: {
|
|
24
|
-
type: Boolean,
|
|
25
|
-
default: true,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{ timestamps: true },
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
export default mongoose.model<IExample>("Example", ExampleSchema);
|