nodejs-quickstart-structure 1.9.4 → 1.10.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 (43) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +7 -7
  3. package/bin/index.js +2 -2
  4. package/docs/generateCase.md +160 -164
  5. package/lib/modules/app-setup.js +65 -1
  6. package/lib/prompts.js +1 -1
  7. package/package.json +4 -2
  8. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +25 -11
  9. package/templates/clean-architecture/js/src/interfaces/controllers/{userController.js → userController.js.ejs} +23 -0
  10. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -0
  11. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -0
  12. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -0
  13. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -0
  14. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -0
  15. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +17 -0
  16. package/templates/clean-architecture/ts/src/index.ts.ejs +51 -20
  17. package/templates/clean-architecture/ts/src/interfaces/controllers/{userController.ts → userController.ts.ejs} +28 -1
  18. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -0
  19. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -0
  20. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -0
  21. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +27 -0
  22. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -0
  23. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +15 -0
  24. package/templates/common/README.md.ejs +27 -0
  25. package/templates/common/database/js/mongoose.js.ejs +0 -1
  26. package/templates/common/database/ts/mongoose.ts.ejs +0 -1
  27. package/templates/common/package.json.ejs +4 -1
  28. package/templates/mvc/js/src/controllers/userController.js.ejs +55 -0
  29. package/templates/mvc/js/src/graphql/context.js.ejs +7 -0
  30. package/templates/mvc/js/src/graphql/index.js.ejs +5 -0
  31. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -0
  32. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -0
  33. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -0
  34. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +17 -0
  35. package/templates/mvc/js/src/index.js.ejs +38 -26
  36. package/templates/mvc/ts/src/controllers/userController.ts.ejs +56 -1
  37. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -0
  38. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -0
  39. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -0
  40. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +27 -0
  41. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -0
  42. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +15 -0
  43. package/templates/mvc/ts/src/index.ts.ejs +54 -26
@@ -1,12 +1,19 @@
1
1
  const express = require('express');
2
2
  const cors = require('cors');
3
3
  require('dotenv').config();
4
- <% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { %>const apiRoutes = require('./routes/api');<% } -%>
5
- <% if (communication === 'Kafka') { %>const { connectKafka, sendMessage } = require('./services/kafkaService');<% } -%>
6
- <% if (communication === 'REST APIs') { -%>
4
+ <%_ if (communication === 'REST APIs') { -%>const apiRoutes = require('./routes/api');<%_ } -%>
5
+ <%_ if (communication === 'Kafka') { -%>const { connectKafka, sendMessage } = require('./services/kafkaService');<%_ } -%>
6
+ <%_ if (communication === 'GraphQL') { -%>
7
+ const { ApolloServer } = require('@apollo/server');
8
+ const { expressMiddleware } = require('@apollo/server/express4');
9
+ const { ApolloServerPluginLandingPageLocalDefault } = require('@apollo/server/plugin/landingPage/default');
10
+ const { typeDefs, resolvers } = require('./graphql');
11
+ const { gqlContext } = require('./graphql/context');
12
+ <% } -%>
13
+ <%_ if (communication === 'REST APIs') { -%>
7
14
  const swaggerUi = require('swagger-ui-express');
8
15
  const swaggerSpecs = require('./config/swagger');
9
- <% } -%>
16
+ <%_ } -%>
10
17
 
11
18
  const app = express();
12
19
  const PORT = process.env.PORT || 3000;
@@ -17,22 +24,18 @@ app.use(cors());
17
24
  app.use(express.json());
18
25
  app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } }));
19
26
 
20
- <% if (communication === 'REST APIs') { -%>
27
+ <%_ if (communication === 'REST APIs') { -%>
21
28
  app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
22
- <% } -%>
23
-
24
- <% if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
29
+ <%_ } -%>
30
+ <%_ if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
25
31
  // View Engine Setup
26
32
  const path = require('path');
27
33
  app.set('views', path.join(__dirname, 'views'));
28
34
  app.set('view engine', '<%= viewEngine.toLowerCase() %>');
29
- app.use(express.static(path.join(__dirname, '../public')));<% } -%>
30
-
31
- // Routes
32
- <% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { -%>
35
+ app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
36
+ <%_ if (communication === 'REST APIs') { -%>
33
37
  app.use('/api', apiRoutes);
34
- <% } -%>
35
- <% if (viewEngine && viewEngine !== 'None') { -%>
38
+ <%_ } -%><% if (viewEngine && viewEngine !== 'None') { -%>
36
39
  app.get('/', (req, res) => {
37
40
  res.render('index', {
38
41
  projectName: 'NodeJS Service',
@@ -42,24 +45,33 @@ app.get('/', (req, res) => {
42
45
  });
43
46
  });
44
47
  <% } -%>
45
-
46
48
  app.get('/health', (req, res) => {
47
49
  res.json({ status: 'UP' });
48
50
  });
49
51
 
50
52
  // Start Server Logic
51
53
  const startServer = async () => {
52
- logger.info(`Server running on port ${PORT}`);
54
+ <%_ if (communication === 'GraphQL') { -%>
55
+ // GraphQL Setup
56
+ const server = new ApolloServer({
57
+ typeDefs,
58
+ resolvers,
59
+ plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
60
+ });
61
+ await server.start();
62
+ app.use('/graphql', expressMiddleware(server, { context: gqlContext }));
63
+ <%_ } -%>
64
+ app.listen(PORT, () => {
65
+ logger.info(`Server running on port ${PORT}`);
53
66
  <%_ if (communication === 'Kafka') { -%>
54
- try {
55
- await connectKafka();
56
- logger.info('Kafka connected');
57
- // Demo: Send a test message
58
- await sendMessage('test-topic', 'Hello Kafka from MVC JS!');
59
- } catch (err) {
60
- logger.error('Failed to connect to Kafka:', err);
61
- }
67
+ connectKafka().then(() => {
68
+ logger.info('Kafka connected');
69
+ sendMessage('test-topic', 'Hello Kafka from MVC JS!');
70
+ }).catch(err => {
71
+ logger.error('Failed to connect to Kafka:', err);
72
+ });
62
73
  <%_ } -%>
74
+ });
63
75
  };
64
76
 
65
77
  <%_ if (database !== 'None') { -%>
@@ -78,7 +90,7 @@ const syncDatabase = async () => {
78
90
  logger.info('Database synced');
79
91
 
80
92
  // Start Server after DB is ready
81
- app.listen(PORT, startServer);
93
+ await startServer();
82
94
  break;
83
95
  } catch (err) {
84
96
  logger.error('Database sync failed:', err);
@@ -91,5 +103,5 @@ const syncDatabase = async () => {
91
103
 
92
104
  syncDatabase();
93
105
  <%_ } else { -%>
94
- app.listen(PORT, startServer);
106
+ startServer();
95
107
  <%_ } -%>
@@ -1,6 +1,8 @@
1
+ <% if (communication !== 'GraphQL') { -%>
1
2
  import { Request, Response } from 'express';
2
- import User from '@/models/User';
3
3
  import { HTTP_STATUS } from '@/utils/httpCodes';
4
+ <% } -%>
5
+ import User from '@/models/User';
4
6
  import logger from '@/utils/logger';
5
7
  <%_ if (caching === 'Redis') { -%>
6
8
  import cacheService from '@/config/redisClient';
@@ -9,6 +11,58 @@ import cacheService from '@/config/memoryCache';
9
11
  <%_ } -%>
10
12
 
11
13
  export class UserController {
14
+ <% if (communication === 'GraphQL') { -%>
15
+ async getUsers() {
16
+ try {
17
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
18
+ const users = await cacheService.getOrSet('users:all', async () => {
19
+ <%_ if (database === 'MongoDB') { -%>
20
+ return await User.find();
21
+ <%_ } else if (database === 'None') { -%>
22
+ return User.mockData;
23
+ <%_ } else { -%>
24
+ return await User.findAll();
25
+ <%_ } -%>
26
+ }, 60);
27
+ <%_ } else { -%>
28
+ <%_ if (database === 'MongoDB') { -%>
29
+ const users = await User.find();
30
+ <%_ } else if (database === 'None') { -%>
31
+ const users = User.mockData;
32
+ <%_ } else { -%>
33
+ const users = await User.findAll();
34
+ <%_ } -%>
35
+ <%_ } -%>
36
+ return users;
37
+ } catch (error) {
38
+ logger.error('Error fetching users:', error);
39
+ throw error;
40
+ }
41
+ }
42
+
43
+ async createUser(data: { name: string, email: string }) {
44
+ try {
45
+ const { name, email } = data;
46
+ <%_ if (database === 'None') { -%>
47
+ const newUser = { id: String(User.mockData.length + 1), name, email };
48
+ User.mockData.push(newUser);
49
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
50
+ await cacheService.del('users:all');
51
+ <%_ } -%>
52
+ return newUser;
53
+ <%_ } else { -%>
54
+ const user = await User.create({ name, email });
55
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
56
+ await cacheService.del('users:all');
57
+ <%_ } -%>
58
+ return user;
59
+ <%_ } -%>
60
+ } catch (error) {
61
+ logger.error('Error creating user:', error);
62
+ throw error;
63
+ }
64
+ }
65
+ <% } else { -%>
12
66
  async getUsers(req: Request, res: Response) {
13
67
  try {
14
68
  <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
@@ -67,5 +121,6 @@ export class UserController {
67
121
  }
68
122
  }
69
123
  }
124
+ <% } -%>
70
125
  }
71
126
 
@@ -0,0 +1,12 @@
1
+ import { Request } from 'express';
2
+
3
+ export interface MyContext {
4
+ token?: string;
5
+ // user?: User;
6
+ }
7
+
8
+ export const gqlContext = async ({ req }: { req: Request }): Promise<MyContext> => {
9
+ // Setup authorization or context here
10
+ const token = req.headers.authorization || '';
11
+ return { token };
12
+ };
@@ -0,0 +1,3 @@
1
+ export { typeDefs } from '@/graphql/typeDefs';
2
+ export { resolvers } from '@/graphql/resolvers';
3
+ export { gqlContext, MyContext } from '@/graphql/context';
@@ -0,0 +1,4 @@
1
+ import { mergeResolvers } from '@graphql-tools/merge';
2
+ import { userResolvers } from '@/graphql/resolvers/user.resolvers';
3
+
4
+ export const resolvers = mergeResolvers([userResolvers]);
@@ -0,0 +1,27 @@
1
+ import { GraphQLError } from 'graphql';
2
+ import { UserController } from '@/controllers/userController';
3
+
4
+ const userController = new UserController();
5
+
6
+ export const userResolvers = {
7
+ Query: {
8
+ getAllUsers: async () => {
9
+ try {
10
+ return await userController.getUsers();
11
+ } catch (error: unknown) {
12
+ const message = error instanceof Error ? error.message : 'Internal server error';
13
+ throw new GraphQLError(message, { extensions: { code: 'INTERNAL_SERVER_ERROR' } });
14
+ }
15
+ }
16
+ },
17
+ Mutation: {
18
+ createUser: async (_: unknown, { name, email }: { name: string, email: string }) => {
19
+ try {
20
+ return await userController.createUser({ name, email });
21
+ } catch (error: unknown) {
22
+ const message = error instanceof Error ? error.message : 'Internal server error';
23
+ throw new GraphQLError(message, { extensions: { code: 'INTERNAL_SERVER_ERROR' } });
24
+ }
25
+ }
26
+ }
27
+ };
@@ -0,0 +1,4 @@
1
+ import { mergeTypeDefs } from '@graphql-tools/merge';
2
+ import { userTypes } from '@/graphql/typeDefs/user.types';
3
+
4
+ export const typeDefs = mergeTypeDefs([userTypes]);
@@ -0,0 +1,15 @@
1
+ export const userTypes = `#graphql
2
+ type User {
3
+ id: ID!
4
+ name: String!
5
+ email: String!
6
+ }
7
+
8
+ type Query {
9
+ getAllUsers: [User]
10
+ }
11
+
12
+ type Mutation {
13
+ createUser(name: String!, email: String!): User
14
+ }
15
+ `;
@@ -6,11 +6,19 @@ import rateLimit from 'express-rate-limit';
6
6
  import dotenv from 'dotenv';
7
7
  import logger from '@/utils/logger';
8
8
  import morgan from 'morgan';
9
- <% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { %>import apiRoutes from '@/routes/api';<% } -%>
9
+ <%_ if (communication === 'REST APIs') { -%>
10
+ import apiRoutes from '@/routes/api';<%_ } -%>
10
11
  <% if (communication === 'REST APIs') { %>
11
12
  import swaggerUi from 'swagger-ui-express';
12
13
  import swaggerSpecs from '@/config/swagger';<% } -%>
13
- <% if (communication === 'Kafka') { %>import { KafkaService } from '@/services/kafkaService';<% } -%>
14
+ <%_ if (communication === 'Kafka') { -%>import { KafkaService } from '@/services/kafkaService';<%_ } -%>
15
+ <%_ if (communication === 'GraphQL') { -%>
16
+ import { ApolloServer } from '@apollo/server';
17
+ import { expressMiddleware } from '@apollo/server/express4';
18
+ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
19
+ import { typeDefs, resolvers } from '@/graphql';
20
+ import { gqlContext, MyContext } from '@/graphql/context';
21
+ <% } -%>
14
22
 
15
23
  dotenv.config();
16
24
 
@@ -18,7 +26,21 @@ const app = express();
18
26
  const port = process.env.PORT || 3000;
19
27
 
20
28
  // Security Middleware
29
+ <%_ if (communication === 'GraphQL') { -%>
30
+ app.use(helmet({
31
+ crossOriginEmbedderPolicy: false,
32
+ contentSecurityPolicy: {
33
+ directives: {
34
+ imgSrc: [`'self'`, 'data:', 'apollo-server-landing-page.cdn.apollographql.com'],
35
+ scriptSrc: [`'self'`, `https: 'unsafe-inline'`],
36
+ manifestSrc: [`'self'`, 'apollo-server-landing-page.cdn.apollographql.com'],
37
+ frameSrc: [`'self'`, 'sandbox.embed.apollographql.com'],
38
+ },
39
+ },
40
+ }));
41
+ <%_ } else { -%>
21
42
  app.use(helmet());
43
+ <%_ } -%>
22
44
  app.use(hpp());
23
45
  app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE'] }));
24
46
  const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
@@ -26,23 +48,18 @@ app.use(limiter);
26
48
 
27
49
  app.use(express.json());
28
50
  app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
29
-
30
- <% if (communication === 'REST APIs') { -%>
51
+ <%_ if (communication === 'REST APIs') { -%>
31
52
  app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
32
- <% } -%>
33
-
34
- <% if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
53
+ <%_ } -%>
54
+ <%_ if (viewEngine === 'EJS' || viewEngine === 'Pug') { -%>
35
55
  // View Engine Setup
36
56
  import path from 'path';
37
57
  app.set('views', path.join(__dirname, 'views'));
38
58
  app.set('view engine', '<%= viewEngine.toLowerCase() %>');
39
- app.use(express.static(path.join(__dirname, '../public')));<% } -%>
40
-
41
- // Routes
42
- <% if (communication === 'REST APIs' || (viewEngine && viewEngine !== 'None')) { -%>
59
+ app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
60
+ <%_ if (communication === 'REST APIs') { -%>
43
61
  app.use('/api', apiRoutes);
44
- <% } -%>
45
- <% if (viewEngine && viewEngine !== 'None') { -%>
62
+ <%_ } -%><% if (viewEngine && viewEngine !== 'None') { -%>
46
63
  app.get('/', (req: Request, res: Response) => {
47
64
  res.render('index', {
48
65
  projectName: 'NodeJS Service',
@@ -52,25 +69,36 @@ app.get('/', (req: Request, res: Response) => {
52
69
  });
53
70
  });
54
71
  <% } -%>
55
-
56
72
  app.get('/health', (req: Request, res: Response) => {
57
73
  res.json({ status: 'UP' });
58
74
  });
59
75
 
60
76
  // Start Server Logic
61
77
  const startServer = async () => {
62
- logger.info(`Server running on port ${port}`);
78
+ <%_ if (communication === 'GraphQL') { -%>
79
+ // GraphQL Setup
80
+ const server = new ApolloServer<MyContext>({
81
+ typeDefs,
82
+ resolvers,
83
+ plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
84
+ });
85
+ await server.start();
86
+ app.use('/graphql', expressMiddleware(server, { context: gqlContext }));
87
+ <%_ } -%>
88
+ app.listen(port, () => {
89
+ logger.info(`Server running on port ${port}`);
63
90
  <%_ if (communication === 'Kafka') { -%>
64
- try {
65
- const kafkaService = new KafkaService();
66
- await kafkaService.connect();
67
- logger.info('Kafka connected');
68
- // Demo: Send a test message
69
- await kafkaService.sendMessage('test-topic', 'Hello Kafka from MVC TS!');
70
- } catch (err) {
71
- logger.error('Failed to connect to Kafka:', err);
72
- }
91
+ try {
92
+ const kafkaService = new KafkaService();
93
+ kafkaService.connect().then(() => {
94
+ logger.info('Kafka connected');
95
+ kafkaService.sendMessage('test-topic', 'Hello Kafka from MVC TS!');
96
+ });
97
+ } catch (err) {
98
+ logger.error('Failed to connect to Kafka:', err);
99
+ }
73
100
  <%_ } -%>
101
+ });
74
102
  };
75
103
 
76
104
  <%_ if (database !== 'None') { -%>
@@ -88,7 +116,7 @@ const syncDatabase = async () => {
88
116
  <%_ } -%>
89
117
  logger.info('Database synced');
90
118
  // Start Server after DB is ready
91
- app.listen(port, startServer);
119
+ await startServer();
92
120
  break;
93
121
  } catch (error) {
94
122
  logger.error('Error syncing database:', error);
@@ -101,5 +129,5 @@ const syncDatabase = async () => {
101
129
 
102
130
  syncDatabase();
103
131
  <%_ } else { -%>
104
- app.listen(port, startServer);
132
+ startServer();
105
133
  <%_ } -%>