express-genix 1.1.4 → 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.
- package/LICENSE +21 -0
- package/README.md +204 -259
- package/index.js +229 -113
- package/lib/cleanup.js +41 -129
- package/lib/features.js +239 -0
- package/lib/generator.js +286 -204
- package/lib/utils.js +43 -91
- package/package.json +81 -63
- package/templates/cicd/github-actions.yml.ejs +70 -0
- package/templates/config/database.mongo.js.ejs +29 -33
- package/templates/config/database.postgres.js.ejs +41 -40
- package/templates/config/database.prisma.js.ejs +26 -0
- package/templates/config/redis.js.ejs +28 -0
- package/templates/config/schema.prisma.ejs +20 -0
- package/templates/config/swagger.js.ejs +30 -0
- package/templates/config/websocket.js.ejs +62 -0
- package/templates/controllers/authController.js.ejs +152 -129
- package/templates/controllers/exampleController.js.ejs +92 -152
- package/templates/controllers/userController.js.ejs +52 -60
- package/templates/core/Dockerfile.ejs +41 -31
- package/templates/core/README.md.ejs +191 -179
- package/templates/core/app.js.ejs +114 -64
- package/templates/core/docker-compose.yml.ejs +59 -47
- package/templates/core/dockerignore.ejs +7 -0
- package/templates/core/env.ejs +25 -19
- package/templates/core/env.example.ejs +26 -0
- package/templates/core/eslintrc.json.ejs +50 -20
- package/templates/core/gitignore.ejs +51 -51
- package/templates/core/healthcheck.js.ejs +24 -24
- package/templates/core/jest.config.js.ejs +19 -22
- package/templates/core/package.json.ejs +70 -33
- package/templates/core/prettierrc.json.ejs +11 -11
- package/templates/core/server.js.ejs +64 -48
- package/templates/core/tsconfig.json.ejs +19 -0
- package/templates/middleware/auth.js.ejs +80 -66
- package/templates/middleware/cache.js.ejs +67 -0
- package/templates/middleware/errorHandler.js.ejs +50 -46
- package/templates/middleware/requestId.js.ejs +9 -0
- package/templates/middleware/validation.js.ejs +109 -47
- package/templates/migrations/create-users.js.ejs +50 -0
- package/templates/migrations/seed-users.js.ejs +34 -0
- package/templates/migrations/sequelizerc.ejs +8 -0
- package/templates/models/User.mongo.js.ejs +29 -29
- package/templates/models/User.postgres.js.ejs +40 -40
- package/templates/models/index.mongo.js.ejs +7 -7
- package/templates/models/index.postgres.js.ejs +11 -11
- package/templates/routes/authRoutes.js.ejs +222 -13
- package/templates/routes/exampleRoutes.js.ejs +100 -12
- package/templates/routes/index.js.ejs +34 -24
- package/templates/routes/userRoutes.js.ejs +78 -15
- package/templates/services/authService.js.ejs +111 -35
- package/templates/services/exampleService.js.ejs +112 -112
- package/templates/services/userService.mongodb.js.ejs +33 -33
- package/templates/services/userService.postgres.js.ejs +30 -30
- package/templates/services/userService.prisma.js.ejs +36 -0
- package/templates/tests/auth.test.js.ejs +83 -66
- package/templates/tests/example.test.js.ejs +109 -112
- package/templates/tests/setup.js.ejs +11 -11
- package/templates/tests/users.test.js.ejs +42 -42
- package/templates/utils/envValidator.js.ejs +23 -0
- package/templates/utils/errors.js.ejs +12 -12
- package/templates/utils/logger.js.ejs +37 -28
- package/templates/utils/response.js.ejs +28 -0
- package/templates/utils/validators.js.ejs +34 -34
- package/templates/config/swagger.json.ejs +0 -194
- package/templates/core/index.js.ejs +0 -24
|
@@ -1,32 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
RUN
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
FROM node:20-alpine
|
|
2
|
+
|
|
3
|
+
# Set working directory
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Copy package files
|
|
7
|
+
COPY package*.json ./
|
|
8
|
+
<% if (isPrisma) { %>
|
|
9
|
+
# Copy Prisma schema for generation
|
|
10
|
+
COPY prisma ./prisma/
|
|
11
|
+
<% } %>
|
|
12
|
+
# Install dependencies
|
|
13
|
+
RUN npm ci --only=production && npm cache clean --force
|
|
14
|
+
<% if (isPrisma) { %>
|
|
15
|
+
# Generate Prisma client
|
|
16
|
+
RUN npx prisma generate
|
|
17
|
+
<% } %><% if (isTypescript) { %>
|
|
18
|
+
# Copy source and build
|
|
19
|
+
COPY tsconfig.json ./
|
|
20
|
+
COPY src ./src/
|
|
21
|
+
RUN npx tsc
|
|
22
|
+
<% } else { %>
|
|
23
|
+
# Copy application code
|
|
24
|
+
COPY . .
|
|
25
|
+
<% } %>
|
|
26
|
+
# Create non-root user
|
|
27
|
+
RUN addgroup -g 1001 -S nodejs
|
|
28
|
+
RUN adduser -S nodeuser -u 1001
|
|
29
|
+
|
|
30
|
+
# Change ownership of app directory
|
|
31
|
+
RUN chown -R nodeuser:nodejs /app
|
|
32
|
+
USER nodeuser
|
|
33
|
+
|
|
34
|
+
# Expose port
|
|
35
|
+
EXPOSE 3000
|
|
36
|
+
|
|
37
|
+
# Health check
|
|
38
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
39
|
+
CMD node healthcheck.js
|
|
40
|
+
|
|
41
|
+
# Start application
|
|
32
42
|
CMD ["npm", "start"]
|
|
@@ -1,179 +1,191 @@
|
|
|
1
|
-
# <%= projectName %>
|
|
2
|
-
|
|
3
|
-
A production-grade Express.js
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
<% if (
|
|
8
|
-
|
|
9
|
-
- **User Management**:
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
1
|
+
# <%= projectName %>
|
|
2
|
+
|
|
3
|
+
A production-grade Express.js application generated by [express-genix](https://www.npmjs.com/package/express-genix).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
<% if (isTypescript) { %>- **TypeScript**: Full type safety with TypeScript
|
|
8
|
+
<% } %><% if (hasAuth) { %>- **Authentication**: JWT-based auth with access & refresh tokens, token blacklist logout
|
|
9
|
+
- **User Management**: Registration, login, profile CRUD
|
|
10
|
+
<% } %><% if (hasDatabase) { %>- **Database**: <%= db === 'mongodb' ? 'MongoDB with Mongoose' : (isPrisma ? 'PostgreSQL with Prisma ORM' : 'PostgreSQL with Sequelize') %>
|
|
11
|
+
<% } else { %>- **No Database**: Lightweight API with in-memory storage (easily replaceable)
|
|
12
|
+
<% } %><% if (hasRateLimit) { %>- **Rate Limiting**: Configurable request throttling
|
|
13
|
+
<% } %><% if (hasSwagger) { %>- **API Documentation**: Swagger UI with swagger-jsdoc annotations
|
|
14
|
+
<% } %><% if (hasRequestId) { %>- **Request ID**: Correlation ID tracking per request
|
|
15
|
+
<% } %>- **Security**: Helmet, CORS, input sanitization
|
|
16
|
+
- **Logging**: <%= logger === 'pino' ? 'Pino (fast, structured)' : 'Winston (feature-rich)' %> with Morgan HTTP logger
|
|
17
|
+
- **Testing**: Jest + Supertest with coverage
|
|
18
|
+
- **Code Quality**: ESLint (Airbnb) + Prettier
|
|
19
|
+
<% if (hasDocker) { %>- **Docker**: Multi-stage Dockerfile + docker-compose
|
|
20
|
+
<% } %><% if (hasCicd) { %>- **CI/CD**: GitHub Actions workflow
|
|
21
|
+
<% } %>- **Production**: Clustering, graceful shutdown, environment validation
|
|
22
|
+
|
|
23
|
+
## Project Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
<%= projectName %>/
|
|
27
|
+
├── src/
|
|
28
|
+
│ ├── config/ # Database, Swagger configuration
|
|
29
|
+
│ ├── controllers/ # Route handlers
|
|
30
|
+
│ ├── middleware/ # Auth, validation, error handling<% if (hasDatabase && !isPrisma) { %>
|
|
31
|
+
│ ├── models/ # Database models<% } %>
|
|
32
|
+
│ ├── routes/ # API route definitions
|
|
33
|
+
│ ├── services/ # Business logic
|
|
34
|
+
│ ├── utils/ # Helpers (logger, errors, response, validators)
|
|
35
|
+
│ ├── app.<%= isTypescript ? 'ts' : 'js' %> # Express app setup
|
|
36
|
+
│ └── server.<%= isTypescript ? 'ts' : 'js' %> # Server + clustering
|
|
37
|
+
├── tests/ # Test suites<% if (isPrisma) { %>
|
|
38
|
+
├── prisma/
|
|
39
|
+
│ └── schema.prisma # Prisma schema<% } %><% if (hasCicd) { %>
|
|
40
|
+
├── .github/workflows/ # CI/CD pipeline<% } %>
|
|
41
|
+
├── .env # Environment variables (do not commit)
|
|
42
|
+
├── .env.example # Environment template
|
|
43
|
+
└── package.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Getting Started
|
|
47
|
+
|
|
48
|
+
### Prerequisites
|
|
49
|
+
|
|
50
|
+
- Node.js >= 18
|
|
51
|
+
- npm >= 9<% if (db === 'mongodb') { %>
|
|
52
|
+
- MongoDB (local or cloud)<% } else if (hasDatabase) { %>
|
|
53
|
+
- PostgreSQL 15+<% } %>
|
|
54
|
+
|
|
55
|
+
### Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm install
|
|
59
|
+
```
|
|
60
|
+
<% if (isPrisma) { %>
|
|
61
|
+
### Database Setup
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Generate Prisma client
|
|
65
|
+
npx prisma generate
|
|
66
|
+
|
|
67
|
+
# Run migrations
|
|
68
|
+
npx prisma migrate dev --name init
|
|
69
|
+
|
|
70
|
+
# Open Prisma Studio (optional)
|
|
71
|
+
npx prisma studio
|
|
72
|
+
```
|
|
73
|
+
<% } else if (db === 'mongodb') { %>
|
|
74
|
+
### Database Setup
|
|
75
|
+
|
|
76
|
+
Ensure MongoDB is running locally or update `MONGO_URI` in `.env`.
|
|
77
|
+
<% } else if (db === 'postgresql') { %>
|
|
78
|
+
### Database Setup
|
|
79
|
+
|
|
80
|
+
Create a PostgreSQL database and update `DATABASE_URL` in `.env`. The schema syncs automatically in development.
|
|
81
|
+
<% } %>
|
|
82
|
+
### Environment
|
|
83
|
+
|
|
84
|
+
Copy `.env.example` to `.env` and update values for your environment:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cp .env.example .env
|
|
88
|
+
```
|
|
89
|
+
<% if (hasAuth) { %>
|
|
90
|
+
> **Important**: Change `JWT_SECRET` and `JWT_REFRESH_SECRET` before deploying.
|
|
91
|
+
<% } %>
|
|
92
|
+
### Development
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm run dev
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Production
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm start
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Available Scripts
|
|
105
|
+
|
|
106
|
+
| Script | Description |
|
|
107
|
+
|--------|-------------|
|
|
108
|
+
| `npm run dev` | Development server with auto-reload |
|
|
109
|
+
| `npm start` | Production server with clustering |
|
|
110
|
+
| `npm test` | Run tests with coverage |
|
|
111
|
+
| `npm run lint` | Check for linting errors |
|
|
112
|
+
| `npm run lint:fix` | Auto-fix linting errors |
|
|
113
|
+
| `npm run format` | Format code with Prettier |
|
|
114
|
+
| `npm run format:check` | Check formatting |<% if (isTypescript) { %>
|
|
115
|
+
| `npm run build` | Compile TypeScript |<% } %><% if (isPrisma) { %>
|
|
116
|
+
| `npx prisma studio` | Open Prisma Studio |
|
|
117
|
+
| `npx prisma migrate dev` | Run database migrations |<% } %>
|
|
118
|
+
<% if (hasSwagger) { %>
|
|
119
|
+
## API Documentation
|
|
120
|
+
|
|
121
|
+
Interactive docs available at [http://localhost:3000/api-docs](http://localhost:3000/api-docs)
|
|
122
|
+
<% } %>
|
|
123
|
+
## API Endpoints
|
|
124
|
+
|
|
125
|
+
<% if (hasAuth) { %>### Authentication
|
|
126
|
+
|
|
127
|
+
| Method | Endpoint | Description |
|
|
128
|
+
|--------|----------|-------------|
|
|
129
|
+
| POST | `/api/auth/register` | Register a new user |
|
|
130
|
+
| POST | `/api/auth/login` | Login and receive tokens |
|
|
131
|
+
| POST | `/api/auth/refresh` | Refresh access token |
|
|
132
|
+
| POST | `/api/auth/logout` | Logout (blacklist token) |
|
|
133
|
+
|
|
134
|
+
### Users (protected)
|
|
135
|
+
|
|
136
|
+
| Method | Endpoint | Description |
|
|
137
|
+
|--------|----------|-------------|
|
|
138
|
+
| GET | `/api/users/profile` | Get current user profile |
|
|
139
|
+
| PUT | `/api/users/profile` | Update profile |
|
|
140
|
+
| DELETE | `/api/users/profile` | Delete account |
|
|
141
|
+
<% } else { %>### Examples
|
|
142
|
+
|
|
143
|
+
| Method | Endpoint | Description |
|
|
144
|
+
|--------|----------|-------------|
|
|
145
|
+
| GET | `/api/examples` | List all (paginated) |
|
|
146
|
+
| GET | `/api/examples/:id` | Get by ID |
|
|
147
|
+
| POST | `/api/examples` | Create |
|
|
148
|
+
| PUT | `/api/examples/:id` | Update |
|
|
149
|
+
| DELETE | `/api/examples/:id` | Delete |
|
|
150
|
+
<% } %>
|
|
151
|
+
### Health
|
|
152
|
+
|
|
153
|
+
| Method | Endpoint | Description |
|
|
154
|
+
|--------|----------|-------------|
|
|
155
|
+
| GET | `/health` | Health check |
|
|
156
|
+
|
|
157
|
+
## Environment Variables
|
|
158
|
+
|
|
159
|
+
| Variable | Description | Default |
|
|
160
|
+
|----------|-------------|---------|
|
|
161
|
+
| `NODE_ENV` | Environment | `development` |
|
|
162
|
+
| `PORT` | Server port | `3000` |<% if (hasAuth) { %>
|
|
163
|
+
| `JWT_SECRET` | Access token secret | *(required)* |
|
|
164
|
+
| `JWT_REFRESH_SECRET` | Refresh token secret | *(required)* |
|
|
165
|
+
| `JWT_EXPIRE` | Access token TTL | `15m` |
|
|
166
|
+
| `JWT_REFRESH_EXPIRE` | Refresh token TTL | `7d` |<% } %><% if (db === 'mongodb') { %>
|
|
167
|
+
| `MONGO_URI` | MongoDB connection string | *(required)* |<% } else if (hasDatabase) { %>
|
|
168
|
+
| `DATABASE_URL` | PostgreSQL connection string | *(required)* |<% } %><% if (hasRateLimit) { %>
|
|
169
|
+
| `RATE_LIMIT_WINDOW_MS` | Rate limit window (ms) | `900000` |
|
|
170
|
+
| `RATE_LIMIT_MAX` | Max requests per window | `100` |<% } %>
|
|
171
|
+
<% if (hasDocker) { %>
|
|
172
|
+
## Docker
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Build and run with docker-compose
|
|
176
|
+
docker-compose up --build
|
|
177
|
+
|
|
178
|
+
# Or build manually
|
|
179
|
+
docker build -t <%= projectName %> .
|
|
180
|
+
docker run -p 3000:3000 --env-file .env <%= projectName %>
|
|
181
|
+
```
|
|
182
|
+
<% } %>
|
|
183
|
+
## Testing
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm test
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT
|
|
@@ -1,65 +1,115 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const cors = require('cors');
|
|
3
|
-
const helmet = require('helmet');
|
|
4
|
-
const morgan = require('morgan');
|
|
5
|
-
const rateLimit = require('express-rate-limit')
|
|
6
|
-
const swaggerUi = require('swagger-ui-express');
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const routes = require('./routes');
|
|
10
|
-
const errorHandler = require('./middleware/errorHandler');
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
app.use(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
app.use(
|
|
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
|
-
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const cors = require('cors');
|
|
3
|
+
const helmet = require('helmet');
|
|
4
|
+
const morgan = require('morgan');
|
|
5
|
+
<% if (hasRateLimit) { %>const rateLimit = require('express-rate-limit');<% } %>
|
|
6
|
+
<% if (hasSwagger) { %>const swaggerUi = require('swagger-ui-express');
|
|
7
|
+
const swaggerSpec = require('./config/swagger');<% } %>
|
|
8
|
+
<% if (hasRequestId) { %>const { requestId } = require('./middleware/requestId');<% } %>
|
|
9
|
+
const routes = require('./routes');
|
|
10
|
+
const errorHandler = require('./middleware/errorHandler');
|
|
11
|
+
<% if (hasDatabase || hasAuth) { %>const { validateEnv } = require('./utils/envValidator');
|
|
12
|
+
|
|
13
|
+
validateEnv();<% } %>
|
|
14
|
+
|
|
15
|
+
const app = express();
|
|
16
|
+
|
|
17
|
+
// Security middleware
|
|
18
|
+
app.use(helmet());
|
|
19
|
+
app.use(cors({
|
|
20
|
+
origin: process.env.CORS_ORIGIN || '*',
|
|
21
|
+
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
|
|
22
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
23
|
+
}));
|
|
24
|
+
<% if (hasRequestId) { %>
|
|
25
|
+
// Request ID tracking
|
|
26
|
+
app.use(requestId);<% } %>
|
|
27
|
+
|
|
28
|
+
// Logging
|
|
29
|
+
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
|
|
30
|
+
|
|
31
|
+
// Body parsing
|
|
32
|
+
app.use(express.json({ limit: '10mb' }));
|
|
33
|
+
app.use(express.urlencoded({ extended: true }));
|
|
34
|
+
<% if (hasRateLimit) { %>
|
|
35
|
+
// Rate limiting
|
|
36
|
+
const limiter = rateLimit({
|
|
37
|
+
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS, 10) || 15 * 60 * 1000,
|
|
38
|
+
max: parseInt(process.env.RATE_LIMIT_MAX, 10) || 100,
|
|
39
|
+
standardHeaders: true,
|
|
40
|
+
legacyHeaders: false,
|
|
41
|
+
message: { success: false, error: 'Too many requests, please try again later.' },
|
|
42
|
+
});
|
|
43
|
+
app.use(limiter);<% } %>
|
|
44
|
+
|
|
45
|
+
// Health check
|
|
46
|
+
app.get('/health', async (req, res) => {
|
|
47
|
+
const health = {
|
|
48
|
+
status: 'OK',
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
uptime: process.uptime(),
|
|
51
|
+
memoryUsage: Math.round(process.memoryUsage().rss / 1024 / 1024) + ' MB',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const checks = {};
|
|
55
|
+
<% if (db === 'mongodb') { %>
|
|
56
|
+
try {
|
|
57
|
+
const mongoose = require('mongoose');
|
|
58
|
+
checks.database = mongoose.connection.readyState === 1 ? 'connected' : 'disconnected';
|
|
59
|
+
} catch {
|
|
60
|
+
checks.database = 'error';
|
|
61
|
+
}
|
|
62
|
+
<% } else if (db === 'postgresql') { %>
|
|
63
|
+
try {
|
|
64
|
+
const { sequelize } = require('./models');
|
|
65
|
+
await sequelize.authenticate();
|
|
66
|
+
checks.database = 'connected';
|
|
67
|
+
} catch {
|
|
68
|
+
checks.database = 'disconnected';
|
|
69
|
+
}
|
|
70
|
+
<% } else if (isPrisma) { %>
|
|
71
|
+
try {
|
|
72
|
+
const { prisma } = require('./config/database');
|
|
73
|
+
await prisma.$queryRaw\`SELECT 1\`;
|
|
74
|
+
checks.database = 'connected';
|
|
75
|
+
} catch {
|
|
76
|
+
checks.database = 'disconnected';
|
|
77
|
+
}
|
|
78
|
+
<% } %><% if (hasRedis) { %>
|
|
79
|
+
try {
|
|
80
|
+
const { redis } = require('./config/redis');
|
|
81
|
+
await redis.ping();
|
|
82
|
+
checks.redis = 'connected';
|
|
83
|
+
} catch {
|
|
84
|
+
checks.redis = 'disconnected';
|
|
85
|
+
}
|
|
86
|
+
<% } %>
|
|
87
|
+
const allHealthy = Object.values(checks).every((v) => v === 'connected');
|
|
88
|
+
const statusCode = Object.keys(checks).length === 0 || allHealthy ? 200 : 503;
|
|
89
|
+
health.status = statusCode === 200 ? 'OK' : 'DEGRADED';
|
|
90
|
+
health.checks = checks;
|
|
91
|
+
|
|
92
|
+
res.status(statusCode).json({ success: statusCode === 200, data: health });
|
|
93
|
+
});
|
|
94
|
+
<% if (hasSwagger) { %>
|
|
95
|
+
// API documentation
|
|
96
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
|
|
97
|
+
customCss: '.swagger-ui .topbar { display: none }',
|
|
98
|
+
}));<% } %>
|
|
99
|
+
|
|
100
|
+
// API routes
|
|
101
|
+
app.use('/api', routes);
|
|
102
|
+
|
|
103
|
+
// 404 handler
|
|
104
|
+
app.use('*', (req, res) => {
|
|
105
|
+
res.status(404).json({
|
|
106
|
+
success: false,
|
|
107
|
+
error: 'Route not found',
|
|
108
|
+
path: req.originalUrl,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Error handler (must be last)
|
|
113
|
+
app.use(errorHandler);
|
|
114
|
+
|
|
65
115
|
module.exports = app;
|