nodejs-quickstart-structure 1.15.1 → 1.16.1
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/CHANGELOG.md +23 -0
- package/README.md +14 -5
- package/lib/modules/app-setup.js +3 -3
- package/lib/modules/config-files.js +2 -2
- package/lib/modules/kafka-setup.js +70 -24
- package/package.json +1 -1
- package/templates/clean-architecture/js/src/index.js.ejs +9 -6
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +12 -11
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +17 -1
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +36 -0
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +1 -1
- package/templates/clean-architecture/ts/src/index.ts.ejs +16 -16
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +0 -1
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +19 -0
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +17 -0
- package/templates/common/Dockerfile +2 -0
- package/templates/common/README.md.ejs +24 -1
- package/templates/common/database/js/models/User.js.ejs +2 -1
- package/templates/common/database/ts/models/User.ts.ejs +4 -3
- package/templates/common/eslint.config.mjs.ejs +30 -3
- package/templates/common/health/js/healthRoute.js.ejs +5 -2
- package/templates/common/health/ts/healthRoute.ts.ejs +5 -2
- package/templates/common/jest.config.js.ejs +4 -1
- package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -0
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -0
- package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +11 -0
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -0
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +31 -0
- package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +49 -0
- package/templates/common/kafka/js/services/kafkaService.js.ejs +77 -23
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +53 -7
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -0
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -0
- package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -0
- package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +11 -0
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +49 -0
- package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +25 -0
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +22 -2
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +65 -12
- package/templates/common/package.json.ejs +6 -4
- package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +8 -11
- package/templates/mvc/js/src/controllers/userController.js.ejs +15 -0
- package/templates/mvc/js/src/controllers/userController.spec.js.ejs +39 -0
- package/templates/mvc/js/src/index.js.ejs +20 -15
- package/templates/mvc/ts/src/config/swagger.ts.ejs +1 -1
- package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +18 -0
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +16 -0
- package/templates/mvc/ts/src/index.ts.ejs +16 -18
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +0 -1
|
@@ -24,6 +24,20 @@ jest.mock('@/config/memoryCache', () => ({
|
|
|
24
24
|
}));
|
|
25
25
|
<%_ } -%>
|
|
26
26
|
jest.mock('@/utils/logger');
|
|
27
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
28
|
+
jest.mock('@/services/kafkaService', () => {
|
|
29
|
+
const mockSendMessage = jest.fn().mockResolvedValue(undefined);
|
|
30
|
+
return {
|
|
31
|
+
kafkaService: {
|
|
32
|
+
sendMessage: mockSendMessage
|
|
33
|
+
},
|
|
34
|
+
KafkaService: jest.fn().mockImplementation(() => ({
|
|
35
|
+
sendMessage: mockSendMessage
|
|
36
|
+
}))
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
<%_ } -%>
|
|
40
|
+
|
|
27
41
|
|
|
28
42
|
describe('UserController', () => {
|
|
29
43
|
let userController: UserController;
|
|
@@ -158,6 +172,10 @@ describe('UserController', () => {
|
|
|
158
172
|
<% } -%>
|
|
159
173
|
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
160
174
|
expect(cacheService.del).toHaveBeenCalledWith('users:all');
|
|
175
|
+
<%_ } -%>
|
|
176
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
177
|
+
const { kafkaService } = require('@/services/kafkaService');
|
|
178
|
+
expect(kafkaService.sendMessage).toHaveBeenCalled();
|
|
161
179
|
<%_ } -%>
|
|
162
180
|
});
|
|
163
181
|
|
|
@@ -8,6 +8,8 @@ import logger from '@/utils/logger';
|
|
|
8
8
|
import cacheService from '@/config/redisClient';
|
|
9
9
|
<%_ } else if (caching === 'Memory Cache') { -%>
|
|
10
10
|
import cacheService from '@/config/memoryCache';
|
|
11
|
+
<%_ } -%><%_ if (communication === 'Kafka') { -%>
|
|
12
|
+
import { kafkaService } from '@/services/kafkaService';
|
|
11
13
|
<%_ } -%>
|
|
12
14
|
|
|
13
15
|
export class UserController {
|
|
@@ -42,6 +44,13 @@ export class UserController {
|
|
|
42
44
|
const user = await User.create({ name, email });
|
|
43
45
|
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
44
46
|
await cacheService.del('users:all');
|
|
47
|
+
<%_ } -%>
|
|
48
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
49
|
+
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
50
|
+
action: 'USER_CREATED',
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
payload: { id: (user as any).id || (user as any)._id, email: user.email }
|
|
53
|
+
}));
|
|
45
54
|
<%_ } -%>
|
|
46
55
|
return user;
|
|
47
56
|
} catch (error) {
|
|
@@ -80,6 +89,13 @@ export class UserController {
|
|
|
80
89
|
const user = await User.create({ name, email });
|
|
81
90
|
<%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
|
|
82
91
|
await cacheService.del('users:all');
|
|
92
|
+
<%_ } -%>
|
|
93
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
94
|
+
await kafkaService.sendMessage('user-topic', JSON.stringify({
|
|
95
|
+
action: 'USER_CREATED',
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
+
payload: { id: (user as any).id || (user as any)._id, email: user.email }
|
|
98
|
+
}));
|
|
83
99
|
<%_ } -%>
|
|
84
100
|
res.status(HTTP_STATUS.CREATED).json(user);
|
|
85
101
|
} catch (error) {
|
|
@@ -9,12 +9,11 @@ import morgan from 'morgan';
|
|
|
9
9
|
import { errorMiddleware } from '@/utils/errorMiddleware';
|
|
10
10
|
import { setupGracefulShutdown } from '@/utils/gracefulShutdown';
|
|
11
11
|
import healthRoutes from '@/routes/healthRoute';
|
|
12
|
-
<%_ if (communication === 'REST APIs') { -%>
|
|
13
|
-
import apiRoutes from '@/routes/api'
|
|
14
|
-
<% if (communication === 'REST APIs') { %>
|
|
12
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
13
|
+
import apiRoutes from '@/routes/api';
|
|
15
14
|
import swaggerUi from 'swagger-ui-express';
|
|
16
|
-
import swaggerSpecs from '@/config/swagger';<% }
|
|
17
|
-
<%_ if (communication === 'Kafka') { -%>import {
|
|
15
|
+
import swaggerSpecs from '@/config/swagger';<%_ } %>
|
|
16
|
+
<%_ if (communication === 'Kafka') { -%>import { kafkaService } from '@/services/kafkaService';<%_ } -%>
|
|
18
17
|
<%_ if (communication === 'GraphQL') { -%>
|
|
19
18
|
import { ApolloServer } from '@apollo/server';
|
|
20
19
|
import { expressMiddleware } from '@apollo/server/express4';
|
|
@@ -51,7 +50,7 @@ app.use(limiter);
|
|
|
51
50
|
|
|
52
51
|
app.use(express.json());
|
|
53
52
|
app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
|
|
54
|
-
<%_ if (communication === 'REST APIs') { -%>
|
|
53
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
55
54
|
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
56
55
|
<%_ } -%>
|
|
57
56
|
<%_ if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
|
|
@@ -60,7 +59,7 @@ import path from 'path';
|
|
|
60
59
|
app.set('views', path.join(__dirname, 'views'));
|
|
61
60
|
app.set('view engine', '<%= viewEngine.toLowerCase() %>');
|
|
62
61
|
app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
|
|
63
|
-
<%_ if (communication === 'REST APIs') { -%>
|
|
62
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
64
63
|
app.use('/api', apiRoutes);
|
|
65
64
|
<%_ } -%><% if (viewEngine && viewEngine !== 'None') { -%>
|
|
66
65
|
app.get('/', (req: Request, res: Response) => {
|
|
@@ -106,18 +105,16 @@ const startServer = async () => {
|
|
|
106
105
|
app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
|
|
107
106
|
<%_ } -%>
|
|
108
107
|
app.use(errorMiddleware);
|
|
109
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
110
|
-
const kafkaService = new KafkaService();
|
|
111
|
-
<%_ } -%>
|
|
112
108
|
const server = app.listen(port, () => {
|
|
113
109
|
logger.info(`Server running on port ${port}`);
|
|
114
110
|
<%_ if (communication === 'Kafka') { -%>
|
|
115
|
-
kafkaService.connect()
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
kafkaService.connect()
|
|
112
|
+
.then(async () => {
|
|
113
|
+
logger.info('Kafka connected');
|
|
114
|
+
})
|
|
115
|
+
.catch(err => {
|
|
116
|
+
logger.error('Failed to connect to Kafka after retries:', (err as Error).message);
|
|
117
|
+
});
|
|
121
118
|
<%_ } -%>
|
|
122
119
|
});
|
|
123
120
|
|
|
@@ -126,15 +123,16 @@ const startServer = async () => {
|
|
|
126
123
|
|
|
127
124
|
<%_ if (database !== 'None') { -%>
|
|
128
125
|
// Database Sync
|
|
126
|
+
<%_ if (database !== 'None') { -%>
|
|
127
|
+
import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/config/database';
|
|
128
|
+
<%_ } -%>
|
|
129
129
|
const syncDatabase = async () => {
|
|
130
130
|
let retries = 30;
|
|
131
131
|
while (retries) {
|
|
132
132
|
try {
|
|
133
133
|
<%_ if (database === 'MongoDB') { -%>
|
|
134
|
-
const connectDB = (await import('@/config/database')).default;
|
|
135
134
|
await connectDB();
|
|
136
135
|
<%_ } else { -%>
|
|
137
|
-
const sequelize = (await import('@/config/database')).default;
|
|
138
136
|
await sequelize.sync();
|
|
139
137
|
<%_ } -%>
|
|
140
138
|
logger.info('Database synced');
|
|
@@ -56,7 +56,6 @@ describe('Logger', () => {
|
|
|
56
56
|
const winston = require('winston');
|
|
57
57
|
jest.resetModules();
|
|
58
58
|
process.env.NODE_ENV = 'production';
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
60
59
|
require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
61
60
|
expect(winston.format.json).toHaveBeenCalled();
|
|
62
61
|
process.env.NODE_ENV = 'test';
|