nodejs-quickstart-structure 1.19.0 → 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.
Files changed (136) hide show
  1. package/CHANGELOG.md +320 -301
  2. package/LICENSE +15 -15
  3. package/README.md +45 -10
  4. package/bin/index.js +7 -1
  5. package/lib/generator.js +139 -139
  6. package/lib/modules/app-setup.js +401 -401
  7. package/lib/modules/config-files.js +151 -151
  8. package/lib/modules/database-setup.js +116 -116
  9. package/lib/modules/project-setup.js +32 -32
  10. package/lib/prompts.js +100 -100
  11. package/package.json +79 -78
  12. package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
  13. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
  14. package/templates/clean-architecture/js/src/index.js.ejs +55 -55
  15. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
  16. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
  17. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
  18. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
  19. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
  20. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
  21. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
  22. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
  23. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
  24. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
  25. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
  26. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
  27. package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
  28. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
  29. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
  30. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
  31. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
  32. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
  33. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
  34. package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
  35. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
  36. package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
  37. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
  38. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
  39. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
  40. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
  41. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
  42. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
  43. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
  44. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
  45. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
  46. package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
  47. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
  48. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
  49. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  50. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
  51. package/templates/common/.cursorrules.ejs +60 -60
  52. package/templates/common/.dockerignore +12 -12
  53. package/templates/common/.env.example.ejs +41 -41
  54. package/templates/common/.gitlab-ci.yml.ejs +86 -86
  55. package/templates/common/.lintstagedrc +6 -6
  56. package/templates/common/.prettierrc +7 -7
  57. package/templates/common/Dockerfile +73 -73
  58. package/templates/common/Jenkinsfile.ejs +87 -87
  59. package/templates/common/SECURITY.md +20 -20
  60. package/templates/common/_github/workflows/ci.yml.ejs +46 -46
  61. package/templates/common/_github/workflows/security.yml.ejs +36 -36
  62. package/templates/common/_gitignore +5 -5
  63. package/templates/common/_husky/pre-commit +4 -4
  64. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
  65. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
  66. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
  67. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
  68. package/templates/common/caching/js/memoryCache.js.ejs +60 -60
  69. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
  70. package/templates/common/caching/js/redisClient.js.ejs +75 -75
  71. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
  72. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
  73. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
  74. package/templates/common/database/js/database.js.ejs +19 -19
  75. package/templates/common/database/js/database.spec.js.ejs +56 -56
  76. package/templates/common/database/js/mongoose.js.ejs +33 -33
  77. package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
  78. package/templates/common/database/ts/database.spec.ts.ejs +56 -56
  79. package/templates/common/database/ts/database.ts.ejs +21 -21
  80. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
  81. package/templates/common/database/ts/mongoose.ts.ejs +28 -28
  82. package/templates/common/docker-compose.yml.ejs +159 -159
  83. package/templates/common/ecosystem.config.js.ejs +40 -40
  84. package/templates/common/eslint.config.mjs.ejs +77 -77
  85. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
  86. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
  87. package/templates/common/jest.config.js.ejs +32 -32
  88. package/templates/common/kafka/js/config/kafka.js +9 -9
  89. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
  90. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
  91. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
  92. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
  93. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
  94. package/templates/common/kafka/ts/config/kafka.ts +7 -7
  95. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
  96. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
  97. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
  98. package/templates/common/migrate-mongo-config.js.ejs +31 -31
  99. package/templates/common/migrations/init.js.ejs +23 -23
  100. package/templates/common/package.json.ejs +119 -118
  101. package/templates/common/prompts/add-feature.md.ejs +26 -26
  102. package/templates/common/prompts/project-context.md.ejs +43 -43
  103. package/templates/common/prompts/troubleshoot.md.ejs +28 -28
  104. package/templates/common/public/css/style.css +147 -147
  105. package/templates/common/scripts/run-e2e.js.ejs +63 -63
  106. package/templates/common/sonar-project.properties.ejs +27 -27
  107. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
  108. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
  109. package/templates/common/tsconfig.json +22 -22
  110. package/templates/common/views/ejs/index.ejs +55 -55
  111. package/templates/common/views/pug/index.pug +40 -40
  112. package/templates/mvc/js/src/config/env.js.ejs +46 -46
  113. package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
  114. package/templates/mvc/js/src/errors/ApiError.js +14 -14
  115. package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
  116. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
  117. package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
  118. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
  119. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
  120. package/templates/mvc/js/src/index.js.ejs +136 -136
  121. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
  122. package/templates/mvc/js/src/utils/httpCodes.js +9 -9
  123. package/templates/mvc/js/src/utils/logger.js +40 -40
  124. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
  125. package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
  126. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
  127. package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
  128. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
  129. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
  130. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
  131. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
  132. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
  133. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  134. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
  135. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
  136. package/templates/mvc/ts/src/utils/logger.ts +36 -36
@@ -1,36 +1,36 @@
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
- logger.add(new winston.transports.Console({
31
- format: process.env.NODE_ENV !== 'production'
32
- ? winston.format.simple()
33
- : winston.format.json(),
34
- }));
35
-
36
- 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
+ logger.add(new winston.transports.Console({
31
+ format: process.env.NODE_ENV !== 'production'
32
+ ? winston.format.simple()
33
+ : winston.format.json(),
34
+ }));
35
+
36
+ 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('@/infrastructure/log/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('@/infrastructure/log/logger');
60
+ expect(winston.format.json).toHaveBeenCalled();
61
+ process.env.NODE_ENV = 'test';
62
+ });
63
+ });
@@ -1,30 +1,30 @@
1
- const logger = require('../../log/logger');
2
- const { ApiError } = require('../../../errors/ApiError');
3
- const HTTP_STATUS = require('../../../utils/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 };
30
-
1
+ const logger = require('../../log/logger');
2
+ const { ApiError } = require('../../../errors/ApiError');
3
+ const HTTP_STATUS = require('../../../utils/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 };
30
+
@@ -1,89 +1,89 @@
1
- const express = require('express');
2
- const cors = require('cors');
3
- const logger = require('../log/logger');
4
- const morgan = require('morgan');
5
- const { errorMiddleware } = require('./middleware/errorMiddleware');
6
- const healthRoutes = require('../../interfaces/routes/healthRoute');
7
- const setupGracefulShutdown = require('../../utils/gracefulShutdown');
8
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
9
- const apiRoutes = require('../../interfaces/routes/api');
10
- const swaggerUi = require('swagger-ui-express');
11
- const swaggerSpecs = require('./swagger');
12
- <%_ } -%>
13
- <%_ if (communication === 'GraphQL') { -%>
14
- const { ApolloServer } = require('@apollo/server');
15
- const { expressMiddleware } = require('@as-integrations/express4');
16
- const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default');
17
- const { unwrapResolverError } = require('@apollo/server/errors');
18
- const { ApiError } = require('../../errors/ApiError');
19
- const { typeDefs, resolvers } = require('../../interfaces/graphql');
20
- const { gqlContext } = require('../../interfaces/graphql/context');
21
- <%_ } -%>
22
-
23
- const { env } = require('../config/env');
24
-
25
- const startServer = async () => {
26
- // Determine port using the validated env
27
- const port = env.PORT;
28
- const app = express();
29
-
30
- app.use(cors());
31
- app.use(express.json());
32
- app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
33
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
34
- app.use('/api', apiRoutes);
35
- <%_ } -%>
36
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
37
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
38
- <%_ } -%>
39
- <%_ if (communication === 'GraphQL') { -%>
40
- // GraphQL Setup
41
- const apolloServer = new ApolloServer({
42
- typeDefs,
43
- resolvers,
44
- plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
45
- formatError: (formattedError, error) => {
46
- const originalError = unwrapResolverError(error);
47
- if (originalError instanceof ApiError) {
48
- return {
49
- ...formattedError,
50
- message: originalError.message,
51
- extensions: {
52
- ...formattedError.extensions,
53
- code: originalError.statusCode.toString(),
54
- }
55
- };
56
- }
57
-
58
- logger.error(`GraphQL Error: ${formattedError.message}`);
59
- if (originalError && originalError.stack && process.env.NODE_ENV === 'development') {
60
- logger.error(originalError.stack);
61
- }
62
- return formattedError;
63
- },
64
- });
65
- await apolloServer.start();
66
- app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
67
- <%_ } -%>
68
- app.use('/health', healthRoutes);
69
-
70
- app.use(errorMiddleware);
71
-
72
- const server = app.listen(port, () => {
73
- logger.info(`Server running on port ${port}`);
74
- <%_ if (communication === 'Kafka') { -%>
75
- const { connectKafka } = require('../../infrastructure/messaging/kafkaClient');
76
- connectKafka()
77
- .then(async () => {
78
- logger.info('Kafka connected');
79
- })
80
- .catch(err => {
81
- logger.error('Failed to connect to Kafka after retries:', err.message);
82
- });
83
- <%_ } -%>
84
- });
85
-
86
- setupGracefulShutdown(server);
87
- };
88
-
89
- module.exports = startServer;
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const logger = require('../log/logger');
4
+ const morgan = require('morgan');
5
+ const { errorMiddleware } = require('./middleware/errorMiddleware');
6
+ const healthRoutes = require('../../interfaces/routes/healthRoute');
7
+ const setupGracefulShutdown = require('../../utils/gracefulShutdown');
8
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
9
+ const apiRoutes = require('../../interfaces/routes/api');
10
+ const swaggerUi = require('swagger-ui-express');
11
+ const swaggerSpecs = require('./swagger');
12
+ <%_ } -%>
13
+ <%_ if (communication === 'GraphQL') { -%>
14
+ const { ApolloServer } = require('@apollo/server');
15
+ const { expressMiddleware } = require('@as-integrations/express4');
16
+ const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default');
17
+ const { unwrapResolverError } = require('@apollo/server/errors');
18
+ const { ApiError } = require('../../errors/ApiError');
19
+ const { typeDefs, resolvers } = require('../../interfaces/graphql');
20
+ const { gqlContext } = require('../../interfaces/graphql/context');
21
+ <%_ } -%>
22
+
23
+ const { env } = require('../config/env');
24
+
25
+ const startServer = async () => {
26
+ // Determine port using the validated env
27
+ const port = env.PORT;
28
+ const app = express();
29
+
30
+ app.use(cors());
31
+ app.use(express.json());
32
+ app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
33
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
34
+ app.use('/api', apiRoutes);
35
+ <%_ } -%>
36
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
37
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
38
+ <%_ } -%>
39
+ <%_ if (communication === 'GraphQL') { -%>
40
+ // GraphQL Setup
41
+ const apolloServer = new ApolloServer({
42
+ typeDefs,
43
+ resolvers,
44
+ plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
45
+ formatError: (formattedError, error) => {
46
+ const originalError = unwrapResolverError(error);
47
+ if (originalError instanceof ApiError) {
48
+ return {
49
+ ...formattedError,
50
+ message: originalError.message,
51
+ extensions: {
52
+ ...formattedError.extensions,
53
+ code: originalError.statusCode.toString(),
54
+ }
55
+ };
56
+ }
57
+
58
+ logger.error(`GraphQL Error: ${formattedError.message}`);
59
+ if (originalError && originalError.stack && process.env.NODE_ENV === 'development') {
60
+ logger.error(originalError.stack);
61
+ }
62
+ return formattedError;
63
+ },
64
+ });
65
+ await apolloServer.start();
66
+ app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
67
+ <%_ } -%>
68
+ app.use('/health', healthRoutes);
69
+
70
+ app.use(errorMiddleware);
71
+
72
+ const server = app.listen(port, () => {
73
+ logger.info(`Server running on port ${port}`);
74
+ <%_ if (communication === 'Kafka') { -%>
75
+ const { connectKafka } = require('../../infrastructure/messaging/kafkaClient');
76
+ connectKafka()
77
+ .then(async () => {
78
+ logger.info('Kafka connected');
79
+ })
80
+ .catch(err => {
81
+ logger.error('Failed to connect to Kafka after retries:', err.message);
82
+ });
83
+ <%_ } -%>
84
+ });
85
+
86
+ setupGracefulShutdown(server);
87
+ };
88
+
89
+ module.exports = startServer;
@@ -1,6 +1,6 @@
1
- const path = require('path');
2
- const YAML = require('yamljs');
3
-
4
- const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
5
-
6
- module.exports = swaggerDocument;
1
+ const path = require('path');
2
+ const YAML = require('yamljs');
3
+
4
+ const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
5
+
6
+ module.exports = swaggerDocument;
@@ -1,13 +1,13 @@
1
- const UserRepository = require('../../infrastructure/repositories/UserRepository');
2
-
3
- const gqlContext = async ({ req }) => {
4
- const token = req.headers.authorization || '';
5
- const userRepository = new UserRepository();
6
-
7
- return {
8
- token,
9
- userRepository
10
- };
11
- };
12
-
13
- module.exports = { gqlContext };
1
+ const UserRepository = require('../../infrastructure/repositories/UserRepository');
2
+
3
+ const gqlContext = async ({ req }) => {
4
+ const token = req.headers.authorization || '';
5
+ const userRepository = new UserRepository();
6
+
7
+ return {
8
+ token,
9
+ userRepository
10
+ };
11
+ };
12
+
13
+ module.exports = { gqlContext };
@@ -1,31 +1,31 @@
1
- const { gqlContext } = require('@/interfaces/graphql/context');
2
- const { resolvers } = require('@/interfaces/graphql/resolvers');
3
- const { typeDefs } = require('@/interfaces/graphql/typeDefs');
4
-
5
- jest.mock('@/infrastructure/repositories/UserRepository');
6
-
7
- describe('GraphQL Context', () => {
8
- it('should exercise GraphQL index entry points', () => {
9
- expect(resolvers).toBeDefined();
10
- expect(typeDefs).toBeDefined();
11
- });
12
- it('should return context with token when authorization header is present', async () => {
13
- const mockRequest = {
14
- headers: {
15
- authorization: 'Bearer token123',
16
- },
17
- };
18
-
19
- const context = await gqlContext({ req: mockRequest });
20
- expect(context.token).toBe('Bearer token123');
21
- });
22
-
23
- it('should return context with empty token when authorization header is missing', async () => {
24
- const mockRequest = {
25
- headers: {},
26
- };
27
-
28
- const context = await gqlContext({ req: mockRequest });
29
- expect(context.token).toBe('');
30
- });
31
- });
1
+ const { gqlContext } = require('@/interfaces/graphql/context');
2
+ const { resolvers } = require('@/interfaces/graphql/resolvers');
3
+ const { typeDefs } = require('@/interfaces/graphql/typeDefs');
4
+
5
+ jest.mock('@/infrastructure/repositories/UserRepository');
6
+
7
+ describe('GraphQL Context', () => {
8
+ it('should exercise GraphQL index entry points', () => {
9
+ expect(resolvers).toBeDefined();
10
+ expect(typeDefs).toBeDefined();
11
+ });
12
+ it('should return context with token when authorization header is present', async () => {
13
+ const mockRequest = {
14
+ headers: {
15
+ authorization: 'Bearer token123',
16
+ },
17
+ };
18
+
19
+ const context = await gqlContext({ req: mockRequest });
20
+ expect(context.token).toBe('Bearer token123');
21
+ });
22
+
23
+ it('should return context with empty token when authorization header is missing', async () => {
24
+ const mockRequest = {
25
+ headers: {},
26
+ };
27
+
28
+ const context = await gqlContext({ req: mockRequest });
29
+ expect(context.token).toBe('');
30
+ });
31
+ });
@@ -1,5 +1,5 @@
1
- const { typeDefs } = require('./typeDefs');
2
- const { resolvers } = require('./resolvers');
3
- const { gqlContext } = require('./context');
4
-
5
- module.exports = { typeDefs, resolvers, gqlContext };
1
+ const { typeDefs } = require('./typeDefs');
2
+ const { resolvers } = require('./resolvers');
3
+ const { gqlContext } = require('./context');
4
+
5
+ module.exports = { typeDefs, resolvers, gqlContext };
@@ -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 };