nodejs-quickstart-structure 1.19.0 → 1.19.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 +309 -301
- package/LICENSE +15 -15
- package/lib/generator.js +139 -139
- package/lib/modules/app-setup.js +401 -401
- package/lib/modules/config-files.js +151 -151
- package/lib/modules/database-setup.js +116 -116
- package/lib/modules/project-setup.js +32 -32
- package/lib/prompts.js +100 -100
- package/package.json +78 -78
- package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
- package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
- package/templates/clean-architecture/js/src/index.js.ejs +55 -55
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
- package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
- package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
- package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
- package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
- package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
- package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
- package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
- package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
- package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
- package/templates/common/.cursorrules.ejs +60 -60
- package/templates/common/.dockerignore +12 -12
- package/templates/common/.env.example.ejs +41 -41
- package/templates/common/.gitlab-ci.yml.ejs +86 -86
- package/templates/common/.lintstagedrc +6 -6
- package/templates/common/.prettierrc +7 -7
- package/templates/common/Dockerfile +73 -73
- package/templates/common/Jenkinsfile.ejs +87 -87
- package/templates/common/SECURITY.md +20 -20
- package/templates/common/_github/workflows/ci.yml.ejs +46 -46
- package/templates/common/_github/workflows/security.yml.ejs +36 -36
- package/templates/common/_gitignore +5 -5
- package/templates/common/_husky/pre-commit +4 -4
- package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
- package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
- package/templates/common/caching/js/memoryCache.js.ejs +60 -60
- package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
- package/templates/common/caching/js/redisClient.js.ejs +75 -75
- package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
- package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
- package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
- package/templates/common/database/js/database.js.ejs +19 -19
- package/templates/common/database/js/database.spec.js.ejs +56 -56
- package/templates/common/database/js/mongoose.js.ejs +33 -33
- package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
- package/templates/common/database/ts/database.spec.ts.ejs +56 -56
- package/templates/common/database/ts/database.ts.ejs +21 -21
- package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
- package/templates/common/database/ts/mongoose.ts.ejs +28 -28
- package/templates/common/docker-compose.yml.ejs +159 -159
- package/templates/common/ecosystem.config.js.ejs +40 -40
- package/templates/common/eslint.config.mjs.ejs +77 -77
- package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
- package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
- package/templates/common/jest.config.js.ejs +32 -32
- package/templates/common/kafka/js/config/kafka.js +9 -9
- package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
- package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
- package/templates/common/kafka/ts/config/kafka.ts +7 -7
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
- package/templates/common/migrate-mongo-config.js.ejs +31 -31
- package/templates/common/migrations/init.js.ejs +23 -23
- package/templates/common/package.json.ejs +119 -118
- package/templates/common/prompts/add-feature.md.ejs +26 -26
- package/templates/common/prompts/project-context.md.ejs +43 -43
- package/templates/common/prompts/troubleshoot.md.ejs +28 -28
- package/templates/common/public/css/style.css +147 -147
- package/templates/common/scripts/run-e2e.js.ejs +63 -63
- package/templates/common/sonar-project.properties.ejs +27 -27
- package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
- package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
- package/templates/common/tsconfig.json +22 -22
- package/templates/common/views/ejs/index.ejs +55 -55
- package/templates/common/views/pug/index.pug +40 -40
- package/templates/mvc/js/src/config/env.js.ejs +46 -46
- package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
- package/templates/mvc/js/src/errors/ApiError.js +14 -14
- package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
- package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
- package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
- package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/mvc/js/src/index.js.ejs +136 -136
- package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
- package/templates/mvc/js/src/utils/httpCodes.js +9 -9
- package/templates/mvc/js/src/utils/logger.js +40 -40
- package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
- package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
- package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
- package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
- package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
- package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
- package/templates/mvc/ts/src/utils/logger.ts +36 -36
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const { mergeResolvers } = require('@graphql-tools/merge');
|
|
2
|
-
const { userResolvers } = require('./user.resolvers');
|
|
3
|
-
|
|
4
|
-
const resolvers = mergeResolvers([userResolvers]);
|
|
5
|
-
|
|
6
|
-
module.exports = { resolvers };
|
|
1
|
+
const { mergeResolvers } = require('@graphql-tools/merge');
|
|
2
|
+
const { userResolvers } = require('./user.resolvers');
|
|
3
|
+
|
|
4
|
+
const resolvers = mergeResolvers([userResolvers]);
|
|
5
|
+
|
|
6
|
+
module.exports = { resolvers };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const { mergeTypeDefs } = require('@graphql-tools/merge');
|
|
2
|
-
const { userTypes } = require('./user.types');
|
|
3
|
-
|
|
4
|
-
const typeDefs = mergeTypeDefs([userTypes]);
|
|
5
|
-
|
|
6
|
-
module.exports = { typeDefs };
|
|
1
|
+
const { mergeTypeDefs } = require('@graphql-tools/merge');
|
|
2
|
+
const { userTypes } = require('./user.types');
|
|
3
|
+
|
|
4
|
+
const typeDefs = mergeTypeDefs([userTypes]);
|
|
5
|
+
|
|
6
|
+
module.exports = { typeDefs };
|
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
const { env } = require('./config/env');
|
|
2
|
-
const express = require('express');
|
|
3
|
-
const cors = require('cors');
|
|
4
|
-
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>const apiRoutes = require('./routes/api');<%_ } %>
|
|
5
|
-
const healthRoutes = require('./routes/healthRoute');
|
|
6
|
-
<%_ if (communication === 'Kafka') { -%>const { connectKafka, sendMessage } = require('./services/kafkaService');<%_ } -%>
|
|
7
|
-
<%_ if (communication === 'GraphQL') { -%>
|
|
8
|
-
const { ApolloServer } = require('@apollo/server');
|
|
9
|
-
const { expressMiddleware } = require('@as-integrations/express4');
|
|
10
|
-
const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default');
|
|
11
|
-
const { unwrapResolverError } = require('@apollo/server/errors');
|
|
12
|
-
const { ApiError } = require('./errors/ApiError');
|
|
13
|
-
const { typeDefs, resolvers } = require('./graphql');
|
|
14
|
-
const { gqlContext } = require('./graphql/context');
|
|
15
|
-
<% } %>
|
|
16
|
-
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
17
|
-
const swaggerUi = require('swagger-ui-express');
|
|
18
|
-
const swaggerSpecs = require('./config/swagger');
|
|
19
|
-
<%_ } -%>
|
|
20
|
-
const setupGracefulShutdown = require('./utils/gracefulShutdown');
|
|
21
|
-
|
|
22
|
-
const app = express();
|
|
23
|
-
const PORT = env.PORT;
|
|
24
|
-
const logger = require('./utils/logger');
|
|
25
|
-
const morgan = require('morgan');
|
|
26
|
-
const { errorMiddleware } = require('./utils/errorMiddleware');
|
|
27
|
-
|
|
28
|
-
app.use(cors());
|
|
29
|
-
app.use(express.json());
|
|
30
|
-
app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
|
|
31
|
-
|
|
32
|
-
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
33
|
-
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
34
|
-
<%_ } -%>
|
|
35
|
-
<%_ if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
|
|
36
|
-
// View Engine Setup
|
|
37
|
-
const path = require('path');
|
|
38
|
-
app.set('views', path.join(__dirname, 'views'));
|
|
39
|
-
app.set('view engine', '<%= viewEngine.toLowerCase() %>');
|
|
40
|
-
app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
|
|
41
|
-
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
42
|
-
app.use('/api', apiRoutes);
|
|
43
|
-
<%_ } -%><% if (viewEngine && viewEngine !== 'None') { -%>
|
|
44
|
-
app.get('/', (req, res) => {
|
|
45
|
-
res.render('index', {
|
|
46
|
-
projectName: 'NodeJS Service',
|
|
47
|
-
architecture: 'MVC',
|
|
48
|
-
database: '<%= database %>',
|
|
49
|
-
communication: '<%= communication %>'
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
<% } -%>
|
|
53
|
-
app.use('/health', healthRoutes);
|
|
54
|
-
|
|
55
|
-
// Start Server Logic
|
|
56
|
-
const startServer = async () => {
|
|
57
|
-
<%_ if (communication === 'GraphQL') { -%>
|
|
58
|
-
// GraphQL Setup
|
|
59
|
-
const apolloServer = new ApolloServer({
|
|
60
|
-
typeDefs,
|
|
61
|
-
resolvers,
|
|
62
|
-
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
|
|
63
|
-
formatError: (formattedError, error) => {
|
|
64
|
-
const originalError = unwrapResolverError(error);
|
|
65
|
-
if (originalError instanceof ApiError) {
|
|
66
|
-
return {
|
|
67
|
-
...formattedError,
|
|
68
|
-
message: originalError.message,
|
|
69
|
-
extensions: {
|
|
70
|
-
...formattedError.extensions,
|
|
71
|
-
code: originalError.statusCode.toString(),
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
logger.error(`GraphQL Error: ${formattedError.message}`);
|
|
77
|
-
if (originalError && originalError.stack && process.env.NODE_ENV === 'development') {
|
|
78
|
-
logger.error(originalError.stack);
|
|
79
|
-
}
|
|
80
|
-
return formattedError;
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
await apolloServer.start();
|
|
84
|
-
app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
|
|
85
|
-
<%_ } -%>
|
|
86
|
-
app.use(errorMiddleware);
|
|
87
|
-
const server = app.listen(PORT, () => {
|
|
88
|
-
logger.info(`Server running on port ${PORT}`);
|
|
89
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
90
|
-
connectKafka()
|
|
91
|
-
.then(async () => {
|
|
92
|
-
logger.info('Kafka connected');
|
|
93
|
-
})
|
|
94
|
-
.catch(err => {
|
|
95
|
-
logger.error('Failed to connect to Kafka after retries:', err.message);
|
|
96
|
-
});
|
|
97
|
-
<%_ } -%>
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
setupGracefulShutdown(server);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
<%_ if (database !== 'None') { -%>
|
|
104
|
-
// Database Sync
|
|
105
|
-
<%_ if (database !== 'None') { -%>
|
|
106
|
-
<%_ if (database === 'MongoDB') { -%>
|
|
107
|
-
const connectDB = require('./config/database');
|
|
108
|
-
<%_ } else { -%>
|
|
109
|
-
const sequelize = require('./config/database');
|
|
110
|
-
<%_ } -%>
|
|
111
|
-
<%_ } -%>
|
|
112
|
-
const syncDatabase = async () => {
|
|
113
|
-
let retries = 30;
|
|
114
|
-
while (retries) {
|
|
115
|
-
try {
|
|
116
|
-
<%_ if (database === 'MongoDB') { -%>
|
|
117
|
-
await connectDB();
|
|
118
|
-
<%_ } else { -%>
|
|
119
|
-
await sequelize.sync();
|
|
120
|
-
<%_ } -%>
|
|
121
|
-
logger.info('Database synced');
|
|
122
|
-
// Start Server after DB is ready
|
|
123
|
-
await startServer();
|
|
124
|
-
break;
|
|
125
|
-
} catch (err) {
|
|
126
|
-
logger.error('Database sync failed:', err);
|
|
127
|
-
retries -= 1;
|
|
128
|
-
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
129
|
-
await new Promise(res => setTimeout(res, 5000));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
syncDatabase();
|
|
135
|
-
<%_ } else { -%>
|
|
136
|
-
startServer();
|
|
1
|
+
const { env } = require('./config/env');
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const cors = require('cors');
|
|
4
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>const apiRoutes = require('./routes/api');<%_ } %>
|
|
5
|
+
const healthRoutes = require('./routes/healthRoute');
|
|
6
|
+
<%_ if (communication === 'Kafka') { -%>const { connectKafka, sendMessage } = require('./services/kafkaService');<%_ } -%>
|
|
7
|
+
<%_ if (communication === 'GraphQL') { -%>
|
|
8
|
+
const { ApolloServer } = require('@apollo/server');
|
|
9
|
+
const { expressMiddleware } = require('@as-integrations/express4');
|
|
10
|
+
const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default');
|
|
11
|
+
const { unwrapResolverError } = require('@apollo/server/errors');
|
|
12
|
+
const { ApiError } = require('./errors/ApiError');
|
|
13
|
+
const { typeDefs, resolvers } = require('./graphql');
|
|
14
|
+
const { gqlContext } = require('./graphql/context');
|
|
15
|
+
<% } %>
|
|
16
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
17
|
+
const swaggerUi = require('swagger-ui-express');
|
|
18
|
+
const swaggerSpecs = require('./config/swagger');
|
|
19
|
+
<%_ } -%>
|
|
20
|
+
const setupGracefulShutdown = require('./utils/gracefulShutdown');
|
|
21
|
+
|
|
22
|
+
const app = express();
|
|
23
|
+
const PORT = env.PORT;
|
|
24
|
+
const logger = require('./utils/logger');
|
|
25
|
+
const morgan = require('morgan');
|
|
26
|
+
const { errorMiddleware } = require('./utils/errorMiddleware');
|
|
27
|
+
|
|
28
|
+
app.use(cors());
|
|
29
|
+
app.use(express.json());
|
|
30
|
+
app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
|
|
31
|
+
|
|
32
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
33
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
|
|
34
|
+
<%_ } -%>
|
|
35
|
+
<%_ if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
|
|
36
|
+
// View Engine Setup
|
|
37
|
+
const path = require('path');
|
|
38
|
+
app.set('views', path.join(__dirname, 'views'));
|
|
39
|
+
app.set('view engine', '<%= viewEngine.toLowerCase() %>');
|
|
40
|
+
app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
|
|
41
|
+
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
42
|
+
app.use('/api', apiRoutes);
|
|
43
|
+
<%_ } -%><% if (viewEngine && viewEngine !== 'None') { -%>
|
|
44
|
+
app.get('/', (req, res) => {
|
|
45
|
+
res.render('index', {
|
|
46
|
+
projectName: 'NodeJS Service',
|
|
47
|
+
architecture: 'MVC',
|
|
48
|
+
database: '<%= database %>',
|
|
49
|
+
communication: '<%= communication %>'
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
<% } -%>
|
|
53
|
+
app.use('/health', healthRoutes);
|
|
54
|
+
|
|
55
|
+
// Start Server Logic
|
|
56
|
+
const startServer = async () => {
|
|
57
|
+
<%_ if (communication === 'GraphQL') { -%>
|
|
58
|
+
// GraphQL Setup
|
|
59
|
+
const apolloServer = new ApolloServer({
|
|
60
|
+
typeDefs,
|
|
61
|
+
resolvers,
|
|
62
|
+
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
|
|
63
|
+
formatError: (formattedError, error) => {
|
|
64
|
+
const originalError = unwrapResolverError(error);
|
|
65
|
+
if (originalError instanceof ApiError) {
|
|
66
|
+
return {
|
|
67
|
+
...formattedError,
|
|
68
|
+
message: originalError.message,
|
|
69
|
+
extensions: {
|
|
70
|
+
...formattedError.extensions,
|
|
71
|
+
code: originalError.statusCode.toString(),
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
logger.error(`GraphQL Error: ${formattedError.message}`);
|
|
77
|
+
if (originalError && originalError.stack && process.env.NODE_ENV === 'development') {
|
|
78
|
+
logger.error(originalError.stack);
|
|
79
|
+
}
|
|
80
|
+
return formattedError;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
await apolloServer.start();
|
|
84
|
+
app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
|
|
85
|
+
<%_ } -%>
|
|
86
|
+
app.use(errorMiddleware);
|
|
87
|
+
const server = app.listen(PORT, () => {
|
|
88
|
+
logger.info(`Server running on port ${PORT}`);
|
|
89
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
90
|
+
connectKafka()
|
|
91
|
+
.then(async () => {
|
|
92
|
+
logger.info('Kafka connected');
|
|
93
|
+
})
|
|
94
|
+
.catch(err => {
|
|
95
|
+
logger.error('Failed to connect to Kafka after retries:', err.message);
|
|
96
|
+
});
|
|
97
|
+
<%_ } -%>
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
setupGracefulShutdown(server);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
<%_ if (database !== 'None') { -%>
|
|
104
|
+
// Database Sync
|
|
105
|
+
<%_ if (database !== 'None') { -%>
|
|
106
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
107
|
+
const connectDB = require('./config/database');
|
|
108
|
+
<%_ } else { -%>
|
|
109
|
+
const sequelize = require('./config/database');
|
|
110
|
+
<%_ } -%>
|
|
111
|
+
<%_ } -%>
|
|
112
|
+
const syncDatabase = async () => {
|
|
113
|
+
let retries = 30;
|
|
114
|
+
while (retries) {
|
|
115
|
+
try {
|
|
116
|
+
<%_ if (database === 'MongoDB') { -%>
|
|
117
|
+
await connectDB();
|
|
118
|
+
<%_ } else { -%>
|
|
119
|
+
await sequelize.sync();
|
|
120
|
+
<%_ } -%>
|
|
121
|
+
logger.info('Database synced');
|
|
122
|
+
// Start Server after DB is ready
|
|
123
|
+
await startServer();
|
|
124
|
+
break;
|
|
125
|
+
} catch (err) {
|
|
126
|
+
logger.error('Database sync failed:', err);
|
|
127
|
+
retries -= 1;
|
|
128
|
+
logger.info(`Retries left: ${retries}. Waiting 5s...`);
|
|
129
|
+
await new Promise(res => setTimeout(res, 5000));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
syncDatabase();
|
|
135
|
+
<%_ } else { -%>
|
|
136
|
+
startServer();
|
|
137
137
|
<%_ } -%>
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
const logger = require('./logger');
|
|
2
|
-
const { ApiError } = require('../errors/ApiError');
|
|
3
|
-
const HTTP_STATUS = require('./httpCodes');
|
|
4
|
-
|
|
5
|
-
// eslint-disable-next-line no-unused-vars
|
|
6
|
-
const errorMiddleware = (err, req, res, next) => {
|
|
7
|
-
let error = err;
|
|
8
|
-
|
|
9
|
-
if (!(error instanceof ApiError)) {
|
|
10
|
-
const statusCode = err.statusCode || HTTP_STATUS.INTERNAL_SERVER_ERROR;
|
|
11
|
-
const message = error.message || 'Internal Server Error';
|
|
12
|
-
error = new ApiError(statusCode, message, false, err.stack);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const { statusCode, message } = error;
|
|
16
|
-
|
|
17
|
-
if (statusCode === HTTP_STATUS.INTERNAL_SERVER_ERROR) {
|
|
18
|
-
logger.error(`${statusCode} - ${message} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
|
|
19
|
-
logger.error(error.stack || 'No stack trace');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
res.status(statusCode).json({
|
|
23
|
-
statusCode,
|
|
24
|
-
message,
|
|
25
|
-
...(process.env.NODE_ENV === 'development' && { stack: error.stack }),
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
module.exports = { errorMiddleware };
|
|
1
|
+
const logger = require('./logger');
|
|
2
|
+
const { ApiError } = require('../errors/ApiError');
|
|
3
|
+
const HTTP_STATUS = require('./httpCodes');
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
const errorMiddleware = (err, req, res, next) => {
|
|
7
|
+
let error = err;
|
|
8
|
+
|
|
9
|
+
if (!(error instanceof ApiError)) {
|
|
10
|
+
const statusCode = err.statusCode || HTTP_STATUS.INTERNAL_SERVER_ERROR;
|
|
11
|
+
const message = error.message || 'Internal Server Error';
|
|
12
|
+
error = new ApiError(statusCode, message, false, err.stack);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { statusCode, message } = error;
|
|
16
|
+
|
|
17
|
+
if (statusCode === HTTP_STATUS.INTERNAL_SERVER_ERROR) {
|
|
18
|
+
logger.error(`${statusCode} - ${message} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
|
|
19
|
+
logger.error(error.stack || 'No stack trace');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
res.status(statusCode).json({
|
|
23
|
+
statusCode,
|
|
24
|
+
message,
|
|
25
|
+
...(process.env.NODE_ENV === 'development' && { stack: error.stack }),
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
module.exports = { errorMiddleware };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const HTTP_STATUS = {
|
|
2
|
-
OK: 200,
|
|
3
|
-
CREATED: 201,
|
|
4
|
-
BAD_REQUEST: 400,
|
|
5
|
-
NOT_FOUND: 404,
|
|
6
|
-
INTERNAL_SERVER_ERROR: 500
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
module.exports = HTTP_STATUS;
|
|
1
|
+
const HTTP_STATUS = {
|
|
2
|
+
OK: 200,
|
|
3
|
+
CREATED: 201,
|
|
4
|
+
BAD_REQUEST: 400,
|
|
5
|
+
NOT_FOUND: 404,
|
|
6
|
+
INTERNAL_SERVER_ERROR: 500
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
module.exports = HTTP_STATUS;
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
const winston = require('winston');
|
|
2
|
-
require('winston-daily-rotate-file');
|
|
3
|
-
|
|
4
|
-
const logger = winston.createLogger({
|
|
5
|
-
level: 'info',
|
|
6
|
-
format: winston.format.combine(
|
|
7
|
-
winston.format.timestamp(),
|
|
8
|
-
winston.format.json()
|
|
9
|
-
),
|
|
10
|
-
defaultMeta: { service: 'user-service' },
|
|
11
|
-
transports: [
|
|
12
|
-
new winston.transports.DailyRotateFile({
|
|
13
|
-
filename: 'logs/error-%DATE%.log',
|
|
14
|
-
datePattern: 'YYYY-MM-DD',
|
|
15
|
-
zippedArchive: true,
|
|
16
|
-
maxSize: '20m',
|
|
17
|
-
maxFiles: '14d',
|
|
18
|
-
level: 'error',
|
|
19
|
-
}),
|
|
20
|
-
new winston.transports.DailyRotateFile({
|
|
21
|
-
filename: 'logs/combined-%DATE%.log',
|
|
22
|
-
datePattern: 'YYYY-MM-DD',
|
|
23
|
-
zippedArchive: true,
|
|
24
|
-
maxSize: '20m',
|
|
25
|
-
maxFiles: '14d',
|
|
26
|
-
}),
|
|
27
|
-
],
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
// If we're not in production then log to the `console` with the format:
|
|
32
|
-
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
|
|
33
|
-
//
|
|
34
|
-
logger.add(new winston.transports.Console({
|
|
35
|
-
format: process.env.NODE_ENV !== 'production'
|
|
36
|
-
? winston.format.simple()
|
|
37
|
-
: winston.format.json(),
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
module.exports = logger;
|
|
1
|
+
const winston = require('winston');
|
|
2
|
+
require('winston-daily-rotate-file');
|
|
3
|
+
|
|
4
|
+
const logger = winston.createLogger({
|
|
5
|
+
level: 'info',
|
|
6
|
+
format: winston.format.combine(
|
|
7
|
+
winston.format.timestamp(),
|
|
8
|
+
winston.format.json()
|
|
9
|
+
),
|
|
10
|
+
defaultMeta: { service: 'user-service' },
|
|
11
|
+
transports: [
|
|
12
|
+
new winston.transports.DailyRotateFile({
|
|
13
|
+
filename: 'logs/error-%DATE%.log',
|
|
14
|
+
datePattern: 'YYYY-MM-DD',
|
|
15
|
+
zippedArchive: true,
|
|
16
|
+
maxSize: '20m',
|
|
17
|
+
maxFiles: '14d',
|
|
18
|
+
level: 'error',
|
|
19
|
+
}),
|
|
20
|
+
new winston.transports.DailyRotateFile({
|
|
21
|
+
filename: 'logs/combined-%DATE%.log',
|
|
22
|
+
datePattern: 'YYYY-MM-DD',
|
|
23
|
+
zippedArchive: true,
|
|
24
|
+
maxSize: '20m',
|
|
25
|
+
maxFiles: '14d',
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
//
|
|
31
|
+
// If we're not in production then log to the `console` with the format:
|
|
32
|
+
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
|
|
33
|
+
//
|
|
34
|
+
logger.add(new winston.transports.Console({
|
|
35
|
+
format: process.env.NODE_ENV !== 'production'
|
|
36
|
+
? winston.format.simple()
|
|
37
|
+
: winston.format.json(),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
module.exports = logger;
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
jest.mock('winston-daily-rotate-file');
|
|
2
|
-
jest.mock('winston', () => {
|
|
3
|
-
const mockLogger = {
|
|
4
|
-
add: jest.fn(),
|
|
5
|
-
info: jest.fn(),
|
|
6
|
-
error: jest.fn(),
|
|
7
|
-
warn: jest.fn()
|
|
8
|
-
};
|
|
9
|
-
const format = {
|
|
10
|
-
combine: jest.fn(),
|
|
11
|
-
timestamp: jest.fn(),
|
|
12
|
-
json: jest.fn(),
|
|
13
|
-
simple: jest.fn()
|
|
14
|
-
};
|
|
15
|
-
const transports = {
|
|
16
|
-
Console: jest.fn(),
|
|
17
|
-
DailyRotateFile: jest.fn()
|
|
18
|
-
};
|
|
19
|
-
return {
|
|
20
|
-
format,
|
|
21
|
-
transports,
|
|
22
|
-
createLogger: jest.fn().mockReturnValue(mockLogger)
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
<% if (architecture === 'MVC') { -%>
|
|
27
|
-
const logger = require('@/utils/logger');
|
|
28
|
-
<% } else { -%>
|
|
29
|
-
const logger = require('@/infrastructure/log/logger');
|
|
30
|
-
<% } -%>
|
|
31
|
-
|
|
32
|
-
describe('Logger', () => {
|
|
33
|
-
it('should export a logger instance', () => {
|
|
34
|
-
expect(logger).toBeDefined();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should have info method', () => {
|
|
38
|
-
expect(typeof logger.info).toBe('function');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should have error method', () => {
|
|
42
|
-
expect(typeof logger.error).toBe('function');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should call info', () => {
|
|
46
|
-
logger.info('test message');
|
|
47
|
-
expect(logger.info).toHaveBeenCalledWith('test message');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should call error', () => {
|
|
51
|
-
logger.error('test error');
|
|
52
|
-
expect(logger.error).toHaveBeenCalledWith('test error');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should use JSON format in production environment', () => {
|
|
56
|
-
const winston = require('winston');
|
|
57
|
-
jest.resetModules();
|
|
58
|
-
process.env.NODE_ENV = 'production';
|
|
59
|
-
require('@/utils/logger');
|
|
60
|
-
expect(winston.format.json).toHaveBeenCalled();
|
|
61
|
-
process.env.NODE_ENV = 'test';
|
|
62
|
-
});
|
|
63
|
-
});
|
|
1
|
+
jest.mock('winston-daily-rotate-file');
|
|
2
|
+
jest.mock('winston', () => {
|
|
3
|
+
const mockLogger = {
|
|
4
|
+
add: jest.fn(),
|
|
5
|
+
info: jest.fn(),
|
|
6
|
+
error: jest.fn(),
|
|
7
|
+
warn: jest.fn()
|
|
8
|
+
};
|
|
9
|
+
const format = {
|
|
10
|
+
combine: jest.fn(),
|
|
11
|
+
timestamp: jest.fn(),
|
|
12
|
+
json: jest.fn(),
|
|
13
|
+
simple: jest.fn()
|
|
14
|
+
};
|
|
15
|
+
const transports = {
|
|
16
|
+
Console: jest.fn(),
|
|
17
|
+
DailyRotateFile: jest.fn()
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
format,
|
|
21
|
+
transports,
|
|
22
|
+
createLogger: jest.fn().mockReturnValue(mockLogger)
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
<% if (architecture === 'MVC') { -%>
|
|
27
|
+
const logger = require('@/utils/logger');
|
|
28
|
+
<% } else { -%>
|
|
29
|
+
const logger = require('@/infrastructure/log/logger');
|
|
30
|
+
<% } -%>
|
|
31
|
+
|
|
32
|
+
describe('Logger', () => {
|
|
33
|
+
it('should export a logger instance', () => {
|
|
34
|
+
expect(logger).toBeDefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should have info method', () => {
|
|
38
|
+
expect(typeof logger.info).toBe('function');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should have error method', () => {
|
|
42
|
+
expect(typeof logger.error).toBe('function');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should call info', () => {
|
|
46
|
+
logger.info('test message');
|
|
47
|
+
expect(logger.info).toHaveBeenCalledWith('test message');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should call error', () => {
|
|
51
|
+
logger.error('test error');
|
|
52
|
+
expect(logger.error).toHaveBeenCalledWith('test error');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should use JSON format in production environment', () => {
|
|
56
|
+
const winston = require('winston');
|
|
57
|
+
jest.resetModules();
|
|
58
|
+
process.env.NODE_ENV = 'production';
|
|
59
|
+
require('@/utils/logger');
|
|
60
|
+
expect(winston.format.json).toHaveBeenCalled();
|
|
61
|
+
process.env.NODE_ENV = 'test';
|
|
62
|
+
});
|
|
63
|
+
});
|