create-backlist 6.1.6 → 6.1.7

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 (36) hide show
  1. package/package.json +1 -1
  2. package/src/analyzer.js +410 -99
  3. package/src/generators/dotnet.js +1 -1
  4. package/src/generators/java.js +154 -97
  5. package/src/generators/node.js +213 -211
  6. package/src/templates/java-spring/partials/ApplicationSeeder.java.ejs +29 -7
  7. package/src/templates/java-spring/partials/AuthController.java.ejs +45 -14
  8. package/src/templates/java-spring/partials/Controller.java.ejs +25 -11
  9. package/src/templates/java-spring/partials/Dockerfile.ejs +25 -3
  10. package/src/templates/java-spring/partials/Entity.java.ejs +28 -3
  11. package/src/templates/java-spring/partials/JwtAuthFilter.java.ejs +41 -7
  12. package/src/templates/java-spring/partials/JwtService.java.ejs +47 -12
  13. package/src/templates/java-spring/partials/Repository.java.ejs +8 -1
  14. package/src/templates/java-spring/partials/Service.java.ejs +30 -6
  15. package/src/templates/java-spring/partials/User.java.ejs +26 -3
  16. package/src/templates/java-spring/partials/UserDetailsServiceImpl.java.ejs +10 -4
  17. package/src/templates/java-spring/partials/UserRepository.java.ejs +6 -0
  18. package/src/templates/java-spring/partials/docker-compose.yml.ejs +27 -5
  19. package/src/templates/node-ts-express/base/server.ts +63 -9
  20. package/src/templates/node-ts-express/base/tsconfig.json +19 -4
  21. package/src/templates/node-ts-express/partials/ApiDocs.ts.ejs +24 -9
  22. package/src/templates/node-ts-express/partials/App.test.ts.ejs +47 -27
  23. package/src/templates/node-ts-express/partials/Auth.controller.ts.ejs +68 -45
  24. package/src/templates/node-ts-express/partials/Auth.middleware.ts.ejs +45 -14
  25. package/src/templates/node-ts-express/partials/Auth.routes.ts.ejs +44 -5
  26. package/src/templates/node-ts-express/partials/Controller.ts.ejs +30 -16
  27. package/src/templates/node-ts-express/partials/Dockerfile.ejs +33 -11
  28. package/src/templates/node-ts-express/partials/Model.cs.ejs +38 -5
  29. package/src/templates/node-ts-express/partials/Model.ts.ejs +42 -12
  30. package/src/templates/node-ts-express/partials/PrismaController.ts.ejs +57 -23
  31. package/src/templates/node-ts-express/partials/PrismaSchema.prisma.ejs +33 -10
  32. package/src/templates/node-ts-express/partials/README.md.ejs +8 -10
  33. package/src/templates/node-ts-express/partials/Seeder.ts.ejs +99 -56
  34. package/src/templates/node-ts-express/partials/docker-compose.yml.ejs +30 -3
  35. package/src/templates/node-ts-express/partials/package.json.ejs +12 -7
  36. package/src/templates/node-ts-express/partials/routes.ts.ejs +31 -18
@@ -1,22 +1,76 @@
1
- import express, { Express, Request, Response } from 'express';
1
+ import express, { Express, Request, Response, NextFunction } from 'express';
2
2
  import cors from 'cors';
3
3
  import dotenv from 'dotenv';
4
+ import helmet from 'helmet';
5
+ import morgan from 'morgan';
4
6
 
5
7
  dotenv.config();
6
8
 
7
- const app: Express = express(); // Added :Express type
9
+ const app: Express = express();
8
10
 
9
- app.use(cors());
10
- app.use(express.json());
11
+ /**
12
+ * Core middleware
13
+ */
14
+ app.use(helmet());
15
+ app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
11
16
 
12
- app.get('/', (req: Request, res: Response) => { // Added :Request and :Response types
17
+ app.use(cors({
18
+ origin: process.env.CORS_ORIGIN
19
+ ? process.env.CORS_ORIGIN.split(',').map(s => s.trim())
20
+ : true,
21
+ credentials: true,
22
+ }));
23
+
24
+ app.use(express.json({ limit: '1mb' }));
25
+
26
+ /**
27
+ * Health + root
28
+ */
29
+ app.get('/api/health', (req: Request, res: Response) => {
30
+ res.status(200).json({ status: 'ok' });
31
+ });
32
+
33
+ app.get('/', (req: Request, res: Response) => {
13
34
  res.send('Node.js Backend says Hello! Generated by Backlist.');
14
35
  });
15
36
 
16
37
  // INJECT:ROUTES
17
38
 
18
- const PORT: number | string = process.env.PORT || 8000; // Added type for PORT
39
+ /**
40
+ * 404 handler (must be after routes)
41
+ */
42
+ app.use((req: Request, res: Response) => {
43
+ res.status(404).json({ message: 'Route not found' });
44
+ });
45
+
46
+ /**
47
+ * Global error handler (must be last)
48
+ */
49
+ app.use((err: any, req: Request, res: Response, _next: NextFunction) => {
50
+ // Log full error on server
51
+ console.error(err);
52
+
53
+ res.status(err?.statusCode || 500).json({
54
+ message: err?.message || 'Internal Server Error',
55
+ });
56
+ });
57
+
58
+ const PORT: number | string = process.env.PORT || 8000;
59
+
60
+ const server = app.listen(PORT, () => {
61
+ console.log(`Server running on http://localhost:${PORT}`);
62
+ });
63
+
64
+ /**
65
+ * Graceful shutdown (Docker / Ctrl+C)
66
+ */
67
+ function shutdown(signal: string) {
68
+ console.log(`Received ${signal}. Shutting down...`);
69
+ server.close(() => {
70
+ console.log('HTTP server closed.');
71
+ process.exit(0);
72
+ });
73
+ }
19
74
 
20
- app.listen(PORT, () => {
21
- console.log(`⚡️ Server running on http://localhost:${PORT}`);
22
- });
75
+ process.on('SIGINT', () => shutdown('SIGINT'));
76
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
@@ -1,10 +1,25 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es6",
4
- "module": "commonjs",
3
+ "target": "ES2020",
4
+ "lib": ["ES2020"],
5
+ "module": "CommonJS",
6
+ "moduleResolution": "Node",
5
7
  "rootDir": "./src",
6
8
  "outDir": "./dist",
9
+
10
+ "strict": true,
7
11
  "esModuleInterop": true,
8
- "strict": true
9
- }
12
+ "forceConsistentCasingInFileNames": true,
13
+ "skipLibCheck": true,
14
+
15
+ "resolveJsonModule": true,
16
+ "sourceMap": true,
17
+
18
+ "noImplicitReturns": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+
21
+ "types": ["node"]
22
+ },
23
+ "include": ["src/**/*.ts"],
24
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
10
25
  }
@@ -1,8 +1,20 @@
1
- // Auto-generated by create-backlist v5.0
1
+ // Auto-generated by Backlist
2
2
  import swaggerUi from 'swagger-ui-express';
3
3
  import swaggerJsdoc from 'swagger-jsdoc';
4
4
  import { Express } from 'express';
5
5
 
6
+ <% if (addAuth) { -%>
7
+ const securitySchemes = {
8
+ bearerAuth: {
9
+ type: 'http',
10
+ scheme: 'bearer',
11
+ bearerFormat: 'JWT',
12
+ },
13
+ };
14
+ <% } else { -%>
15
+ const securitySchemes = {};
16
+ <% } -%>
17
+
6
18
  const options: swaggerJsdoc.Options = {
7
19
  definition: {
8
20
  openapi: '3.0.0',
@@ -13,21 +25,24 @@ const options: swaggerJsdoc.Options = {
13
25
  },
14
26
  servers: [
15
27
  {
16
- url: 'http://localhost:<%= port %>',
17
- description: 'Development server',
28
+ url: process.env.API_BASE_URL || 'http://localhost:<%= port %>',
29
+ description: 'Server',
18
30
  },
19
31
  ],
20
- // TODO: Add components (e.g., securitySchemes for JWT)
32
+ components: {
33
+ securitySchemes: securitySchemes as any,
34
+ },
35
+ // Auto-generated paths (no JSDoc required)
36
+ paths: <%- JSON.stringify(paths || {}, null, 2) %>,
21
37
  },
22
- // Path to the API docs
23
- apis: ['./src/routes/*.ts', './src/routes.ts'], // Looks for JSDoc comments in routes
38
+
39
+ // Keep this too (optional) - if you later add JSDoc annotations
40
+ apis: ['./src/routes/*.ts', './src/routes.ts'],
24
41
  };
25
42
 
26
43
  const swaggerSpec = swaggerJsdoc(options);
27
44
 
28
45
  export function setupSwagger(app: Express) {
29
46
  app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
30
- console.log(
31
- `📄 API documentation is available at http://localhost:<%= port %>/api-docs`
32
- );
47
+ console.log(`API docs: http://localhost:<%= port %>/api-docs`);
33
48
  }
@@ -1,38 +1,58 @@
1
- // Auto-generated by create-backlist v5.0
1
+ // Auto-generated by create-backlist v5.1
2
2
  import request from 'supertest';
3
3
  import express from 'express';
4
- // Import your main app configuration. This might need path adjustment.
5
- // For simplicity, we create a test server here.
6
- import apiRoutes from '../routes'; // Assuming main routes
7
- import authRoutes from '../routes/Auth.routes'; // Assuming auth routes
4
+
5
+ import apiRoutes from '../routes';
6
+
7
+ <% if (addAuth) { -%>
8
+ import authRoutes from '../routes/Auth.routes';
9
+ <% } -%>
8
10
 
9
11
  const app = express();
10
12
  app.use(express.json());
11
- app.use('/api', apiRoutes);
12
- app.use('/api/auth', authRoutes);
13
-
14
13
 
15
- describe('API Endpoints', () => {
14
+ // Mount auth first to avoid conflicts
15
+ <% if (addAuth) { -%>
16
+ app.use('/api/auth', authRoutes);
17
+ <% } -%>
18
+ app.use('/api', apiRoutes);
16
19
 
17
- it('should respond to the root GET endpoint', async () => {
18
- // This test assumes a GET /api/ endpoint exists or a similar public one.
19
- // You might need to adjust this to a real endpoint from your app.
20
- // Example for GET /api/users
21
- // const res = await request(app).get('/api/users');
22
- // expect(res.statusCode).toEqual(200);
23
-
24
- // For now, a placeholder test:
20
+ describe('API Endpoints (Generated)', () => {
21
+ it('sanity check', () => {
25
22
  expect(1 + 1).toBe(2);
26
23
  });
27
24
 
28
- // TODO: Add more specific tests for your generated endpoints
29
- // describe('POST /api/users', () => {
30
- // it('should create a new user', async () => {
31
- // const res = await request(app)
32
- // .post('/api/users')
33
- // .send({ name: 'Test User', email: 'test@example.com', password: 'password123' });
34
- // expect(res.statusCode).toEqual(201);
35
- // expect(res.body).toHaveProperty('name', 'Test User');
36
- // });
37
- // });
25
+ <% endpoints
26
+ .filter(ep => ep && ep.route && ep.method)
27
+ .forEach(ep => {
28
+ const method = String(ep.method).toLowerCase();
29
+
30
+ // make url relative to /api mount
31
+ const url = (String(ep.route).startsWith('/api/')
32
+ ? String(ep.route).replace(/^\/api/, '')
33
+ : String(ep.route)
34
+ )
35
+ // replace path params ":id" with dummy
36
+ .replace(/:\w+/g, '1');
37
+ -%>
38
+ it('<%= ep.method %> <%= url %> should respond', async () => {
39
+ const req = request(app).<%= method %>('<%= '/api' + url %>');
40
+
41
+ <% if (['post','put','patch'].includes(method) && ep.schemaFields) { -%>
42
+ req.send(
43
+ <%- JSON.stringify(
44
+ Object.fromEntries(
45
+ Object.entries(ep.schemaFields).map(([k, t]) => [
46
+ k,
47
+ t === 'Number' ? 1 : (t === 'Boolean' ? true : 'test')
48
+ ])
49
+ )
50
+ ) %>
51
+ );
52
+ <% } -%>
53
+
54
+ const res = await req;
55
+ expect(res.statusCode).not.toBe(404);
56
+ });
57
+ <% }) -%>
38
58
  });
@@ -3,87 +3,110 @@ import { Request, Response } from 'express';
3
3
  import bcrypt from 'bcryptjs';
4
4
  import jwt from 'jsonwebtoken';
5
5
 
6
- <% if (dbType === 'mongoose') { %>
6
+ <% if (dbType === 'mongoose') { -%>
7
7
  import User from '../models/User.model';
8
- <% } else if (dbType === 'prisma') { %>
8
+ <% } else if (dbType === 'prisma') { -%>
9
9
  import { prisma } from '../server';
10
- <% } %>
10
+ <% } -%>
11
+
12
+ function signJwt(payload: any) {
13
+ const secret = process.env.JWT_SECRET;
14
+ if (!secret) {
15
+ throw new Error('JWT_SECRET is not set');
16
+ }
17
+ const expiresIn = process.env.JWT_EXPIRES_IN || '5h';
18
+ return jwt.sign(payload, secret, { expiresIn });
19
+ }
11
20
 
12
21
  // @desc Register a new user
13
22
  export const registerUser = async (req: Request, res: Response) => {
14
- const { name, email, password } = req.body;
23
+ const { name, email, password } = req.body as { name: string; email: string; password: string };
24
+
25
+ if (!name || !email || !password) {
26
+ return res.status(400).json({ message: 'name, email, password are required' });
27
+ }
15
28
 
16
29
  try {
17
- <% if (dbType === 'mongoose') { %>
18
- // Mongoose Logic
19
- let user = await User.findOne({ email });
20
- if (user) {
21
- return res.status(400).json({ message: 'User already exists' });
30
+ <% if (dbType === 'mongoose') { -%>
31
+ const existing = await User.findOne({ email });
32
+ if (existing) {
33
+ return res.status(409).json({ message: 'User already exists' });
22
34
  }
23
- user = new User({ name, email, password });
24
- await user.save();
25
- <% } else if (dbType === 'prisma') { %>
26
- // Prisma Logic
35
+
36
+ const hashedPassword = await bcrypt.hash(password, 10);
37
+
38
+ const user = await User.create({ name, email, password: hashedPassword });
39
+
40
+ const payload = { user: { id: user._id.toString() } };
41
+ const token = signJwt(payload);
42
+
43
+ return res.status(201).json({
44
+ token,
45
+ user: { id: user._id.toString(), name: user.name, email: user.email }
46
+ });
47
+ <% } else if (dbType === 'prisma') { -%>
27
48
  const existingUser = await prisma.user.findUnique({ where: { email } });
28
49
  if (existingUser) {
29
- return res.status(400).json({ message: 'User already exists' });
50
+ return res.status(409).json({ message: 'User already exists' });
30
51
  }
52
+
31
53
  const hashedPassword = await bcrypt.hash(password, 10);
54
+
32
55
  const user = await prisma.user.create({
33
- data: { name, email, password: hashedPassword },
56
+ data: { name, email, password: hashedPassword },
57
+ select: { id: true, name: true, email: true } // never return password
34
58
  });
35
- <% } %>
36
59
 
37
60
  const payload = { user: { id: user.id } };
38
- jwt.sign(
39
- payload,
40
- process.env.JWT_SECRET as string,
41
- { expiresIn: '5h' },
42
- (err, token) => {
43
- if (err) throw err;
44
- res.status(201).json({ token });
45
- }
46
- );
61
+ const token = signJwt(payload);
62
+
63
+ return res.status(201).json({ token, user });
64
+ <% } -%>
47
65
  } catch (error) {
48
66
  console.error(error);
49
- res.status(500).send('Server Error');
67
+ return res.status(500).json({ message: 'Server Error' });
50
68
  }
51
69
  };
52
70
 
53
71
  // @desc Authenticate user & get token (Login)
54
72
  export const loginUser = async (req: Request, res: Response) => {
55
- const { email, password } = req.body;
73
+ const { email, password } = req.body as { email: string; password: string };
74
+
75
+ if (!email || !password) {
76
+ return res.status(400).json({ message: 'email and password are required' });
77
+ }
56
78
 
57
79
  try {
58
- <% if (dbType === 'mongoose') { %>
59
- // Mongoose Logic
80
+ <% if (dbType === 'mongoose') { -%>
60
81
  const user = await User.findOne({ email });
61
- <% } else if (dbType === 'prisma') { %>
62
- // Prisma Logic
82
+ <% } else if (dbType === 'prisma') { -%>
83
+ // Need password for compare
63
84
  const user = await prisma.user.findUnique({ where: { email } });
64
- <% } %>
85
+ <% } -%>
65
86
 
66
87
  if (!user) {
67
- return res.status(400).json({ message: 'Invalid Credentials' });
88
+ return res.status(401).json({ message: 'Invalid Credentials' });
68
89
  }
69
90
 
70
91
  const isMatch = await bcrypt.compare(password, user.password);
71
92
  if (!isMatch) {
72
- return res.status(400).json({ message: 'Invalid Credentials' });
93
+ return res.status(401).json({ message: 'Invalid Credentials' });
73
94
  }
74
95
 
75
- const payload = { user: { id: user.id } };
76
- jwt.sign(
77
- payload,
78
- process.env.JWT_SECRET as string,
79
- { expiresIn: '5h' },
80
- (err, token) => {
81
- if (err) throw err;
82
- res.json({ token });
83
- }
84
- );
96
+ <% if (dbType === 'mongoose') { -%>
97
+ const userId = user._id.toString();
98
+ const safeUser = { id: userId, name: user.name, email: user.email };
99
+ <% } else if (dbType === 'prisma') { -%>
100
+ const userId = user.id;
101
+ const safeUser = { id: user.id, name: user.name, email: user.email };
102
+ <% } -%>
103
+
104
+ const payload = { user: { id: userId } };
105
+ const token = signJwt(payload);
106
+
107
+ return res.json({ token, user: safeUser });
85
108
  } catch (error) {
86
109
  console.error(error);
87
- res.status(500).send('Server Error');
110
+ return res.status(500).json({ message: 'Server Error' });
88
111
  }
89
112
  };
@@ -1,27 +1,58 @@
1
- // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
1
+ // Auto-generated by create-backlist on <%= new Date().toISOString() %>
2
2
  import { Request, Response, NextFunction } from 'express';
3
- import jwt from 'jsonwebtoken';
3
+ import jwt, { JwtPayload } from 'jsonwebtoken';
4
+
5
+ type AuthUser = {
6
+ id: string;
7
+ email?: string;
8
+ role?: string;
9
+ };
4
10
 
5
- // Extend the default Request interface to include our 'user' property
6
11
  interface AuthRequest extends Request {
7
- user?: any;
12
+ user?: AuthUser;
13
+ }
14
+
15
+ function getTokenFromRequest(req: Request): string | null {
16
+ // 1) Standard: Authorization: Bearer <token>
17
+ const authHeader = req.headers.authorization;
18
+ if (authHeader && typeof authHeader === 'string') {
19
+ const [type, token] = authHeader.split(' ');
20
+ if (type?.toLowerCase() === 'bearer' && token) return token.trim();
21
+ }
22
+
23
+ // 2) Fallback: x-auth-token (your old way)
24
+ const xToken = req.header('x-auth-token');
25
+ if (xToken) return xToken.trim();
26
+
27
+ return null;
8
28
  }
9
29
 
10
30
  export const protect = (req: AuthRequest, res: Response, next: NextFunction) => {
11
- // Get token from header
12
- const token = req.header('x-auth-token');
31
+ const token = getTokenFromRequest(req);
13
32
 
14
- // Check if not token
15
33
  if (!token) {
16
- return res.status(401).json({ message: 'No token, authorization denied' });
34
+ return res.status(401).json({ message: 'Authorization token missing' });
35
+ }
36
+
37
+ const secret = process.env.JWT_SECRET;
38
+ if (!secret) {
39
+ // server misconfiguration
40
+ return res.status(500).json({ message: 'JWT_SECRET is not configured' });
17
41
  }
18
42
 
19
- // Verify token
20
43
  try {
21
- const decoded = jwt.verify(token, process.env.JWT_SECRET as string);
22
- req.user = decoded.user;
23
- next();
24
- } catch (err) {
25
- res.status(401).json({ message: 'Token is not valid' });
44
+ const decoded = jwt.verify(token, secret) as JwtPayload;
45
+
46
+ // Expect payload shape: { user: { id: "..." } }
47
+ const user = (decoded as any).user;
48
+
49
+ if (!user?.id) {
50
+ return res.status(401).json({ message: 'Token payload is invalid' });
51
+ }
52
+
53
+ req.user = { id: String(user.id), email: user.email, role: user.role };
54
+ return next();
55
+ } catch {
56
+ return res.status(401).json({ message: 'Token is not valid' });
26
57
  }
27
58
  };
@@ -1,15 +1,54 @@
1
- // Auto-generated by create-backlist v3.0 on <%= new Date().toISOString() %>
1
+ // Auto-generated by create-backlist on <%= new Date().toISOString() %>
2
2
  import { Router } from 'express';
3
3
  import { registerUser, loginUser } from '../controllers/Auth.controller';
4
4
 
5
5
  const router = Router();
6
6
 
7
- // @route POST /api/auth/register
8
- // @desc Register a new user
7
+ /**
8
+ * @openapi
9
+ * /api/auth/register:
10
+ * post:
11
+ * tags: [Auth]
12
+ * summary: Register a new user
13
+ * requestBody:
14
+ * required: true
15
+ * content:
16
+ * application/json:
17
+ * schema:
18
+ * type: object
19
+ * required: [name, email, password]
20
+ * properties:
21
+ * name: { type: string }
22
+ * email: { type: string }
23
+ * password: { type: string }
24
+ * responses:
25
+ * 201: { description: Created }
26
+ * 400: { description: Bad Request }
27
+ * 409: { description: Conflict (User exists) }
28
+ */
9
29
  router.post('/register', registerUser);
10
30
 
11
- // @route POST /api/auth/login
12
- // @desc Authenticate user and get token
31
+ /**
32
+ * @openapi
33
+ * /api/auth/login:
34
+ * post:
35
+ * tags: [Auth]
36
+ * summary: Login and get JWT token
37
+ * requestBody:
38
+ * required: true
39
+ * content:
40
+ * application/json:
41
+ * schema:
42
+ * type: object
43
+ * required: [email, password]
44
+ * properties:
45
+ * email: { type: string }
46
+ * password: { type: string }
47
+ * responses:
48
+ * 200: { description: OK }
49
+ * 400: { description: Bad Request }
50
+ * 401: { description: Unauthorized }
51
+ */
13
52
  router.post('/login', loginUser);
14
53
 
15
54
  export default router;
@@ -1,50 +1,64 @@
1
1
  // Auto-generated by create-backlist on <%= new Date().toISOString() %>
2
2
  import { Request, Response } from 'express';
3
3
 
4
+ const modelLabel = '<%= modelName %>';
5
+
6
+ function serverError(res: Response, action: string, error: unknown) {
7
+ const message = error instanceof Error ? error.message : String(error);
8
+ return res.status(500).json({ success: false, message: `Error ${action} ${modelLabel}`, error: message });
9
+ }
10
+
4
11
  export const create<%= modelName %> = async (req: Request, res: Response) => {
5
12
  try {
6
- // TODO: implement create logic
7
- res.status(201).json({ message: '<%= modelName %> created', data: req.body });
13
+ // TODO: implement create logic (DB)
14
+ return res.status(201).json({ success: true, message: `${modelLabel} created`, data: req.body });
8
15
  } catch (error) {
9
- res.status(500).json({ message: 'Error creating <%= modelName %>', error });
16
+ return serverError(res, 'creating', error);
10
17
  }
11
18
  };
12
19
 
13
- export const getAll<%= modelName %>s = async (_req: Request, res: Response) => {
20
+ export const getAll<%= modelName %>s = async (req: Request, res: Response) => {
14
21
  try {
15
- // TODO: implement list logic
16
- res.status(200).json([]);
22
+ // Optional scaffold for pagination
23
+ const page = Number(req.query.page || 1);
24
+ const limit = Number(req.query.limit || 20);
25
+
26
+ // TODO: implement list logic (DB)
27
+ return res.status(200).json({ success: true, page, limit, data: [] });
17
28
  } catch (error) {
18
- res.status(500).json({ message: 'Error fetching <%= modelName %>s', error });
29
+ return serverError(res, 'fetching', error);
19
30
  }
20
31
  };
21
32
 
22
33
  export const get<%= modelName %>ById = async (req: Request, res: Response) => {
23
34
  try {
24
35
  const { id } = req.params;
25
- // TODO: implement get by id logic
26
- res.status(200).json({ id });
36
+ // TODO: implement get by id logic (DB)
37
+ // If not found: return res.status(404).json({ success:false, message:`${modelLabel} not found` })
38
+ return res.status(200).json({ success: true, data: { id } });
27
39
  } catch (error) {
28
- res.status(500).json({ message: 'Error fetching <%= modelName %>', error });
40
+ return serverError(res, 'fetching', error);
29
41
  }
30
42
  };
31
43
 
32
44
  export const update<%= modelName %>ById = async (req: Request, res: Response) => {
33
45
  try {
34
46
  const { id } = req.params;
35
- // TODO: implement update logic
36
- res.status(200).json({ id, ...req.body });
47
+ // TODO: implement update logic (DB)
48
+ // If not found: return 404
49
+ return res.status(200).json({ success: true, message: `${modelLabel} updated`, data: { id, ...req.body } });
37
50
  } catch (error) {
38
- res.status(500).json({ message: 'Error updating <%= modelName %>', error });
51
+ return serverError(res, 'updating', error);
39
52
  }
40
53
  };
41
54
 
42
55
  export const delete<%= modelName %>ById = async (req: Request, res: Response) => {
43
56
  try {
44
57
  const { id } = req.params;
45
- // TODO: implement delete logic
46
- res.status(204).send();
58
+ // TODO: implement delete logic (DB)
59
+ // If not found: return 404
60
+ return res.status(204).send();
47
61
  } catch (error) {
48
- res.status(500).json({ message: 'Error deleting <%= modelName %>', error });
62
+ return serverError(res, 'deleting', error);
49
63
  }
50
64
  };