build-node-app-personal 1.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 (50) hide show
  1. package/bin/build-node-app.js +114 -0
  2. package/package.json +24 -0
  3. package/template/.env +3 -0
  4. package/template/package.json +16 -0
  5. package/template/server.js +21 -0
  6. package/template/src/app.js +30 -0
  7. package/template/src/config/db.js +19 -0
  8. package/template/src/controllers/userController.js +61 -0
  9. package/template/src/middleware/errorHandler.js +12 -0
  10. package/template/src/middleware/logger.js +14 -0
  11. package/template/src/middleware/notFound.js +8 -0
  12. package/template/src/middleware/userMiddleware.js +13 -0
  13. package/template/src/models/userModel.js +24 -0
  14. package/template/src/routes/userRoutes.js +27 -0
  15. package/template-mysql/.env +7 -0
  16. package/template-mysql/package.json +16 -0
  17. package/template-mysql/server.js +21 -0
  18. package/template-mysql/src/app.js +28 -0
  19. package/template-mysql/src/config/db.js +32 -0
  20. package/template-mysql/src/controllers/userController.js +62 -0
  21. package/template-mysql/src/middleware/errorHandler.js +12 -0
  22. package/template-mysql/src/middleware/logger.js +14 -0
  23. package/template-mysql/src/middleware/notFound.js +8 -0
  24. package/template-mysql/src/middleware/userMiddleware.js +13 -0
  25. package/template-mysql/src/models/userModel.js +39 -0
  26. package/template-mysql/src/routes/userRoutes.js +27 -0
  27. package/template-none/.env +2 -0
  28. package/template-none/package.json +15 -0
  29. package/template-none/server.js +18 -0
  30. package/template-none/src/app.js +24 -0
  31. package/template-none/src/config/db.js +5 -0
  32. package/template-none/src/controllers/userController.js +61 -0
  33. package/template-none/src/middleware/errorHandler.js +12 -0
  34. package/template-none/src/middleware/logger.js +14 -0
  35. package/template-none/src/middleware/notFound.js +8 -0
  36. package/template-none/src/middleware/userMiddleware.js +13 -0
  37. package/template-none/src/models/userModel.js +34 -0
  38. package/template-none/src/routes/userRoutes.js +27 -0
  39. package/template-postgres/.env +7 -0
  40. package/template-postgres/package.json +16 -0
  41. package/template-postgres/server.js +21 -0
  42. package/template-postgres/src/app.js +28 -0
  43. package/template-postgres/src/config/db.js +29 -0
  44. package/template-postgres/src/controllers/userController.js +62 -0
  45. package/template-postgres/src/middleware/errorHandler.js +12 -0
  46. package/template-postgres/src/middleware/logger.js +14 -0
  47. package/template-postgres/src/middleware/notFound.js +8 -0
  48. package/template-postgres/src/middleware/userMiddleware.js +13 -0
  49. package/template-postgres/src/models/userModel.js +35 -0
  50. package/template-postgres/src/routes/userRoutes.js +27 -0
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import url from "url";
7
+
8
+ const program = new Command();
9
+
10
+ const __filename = url.fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ function copyTemplate(targetDir, appName, dbType) {
14
+ let templateFolder;
15
+ switch (dbType) {
16
+ case "mongo":
17
+ templateFolder = "template";
18
+ break;
19
+ case "postgres":
20
+ templateFolder = "template-postgres";
21
+ break;
22
+ case "mysql":
23
+ templateFolder = "template-mysql";
24
+ break;
25
+ case "none":
26
+ templateFolder = "template-none";
27
+ break;
28
+ default:
29
+ console.error(
30
+ "Unsupported database type. Use 'mongo', 'postgres', 'mysql', or 'none'."
31
+ );
32
+ process.exit(1);
33
+ }
34
+ const templateDir = path.join(__dirname, "..", templateFolder);
35
+
36
+ if (!fs.existsSync(templateDir)) {
37
+ console.error("Template directory not found:", templateDir);
38
+ process.exit(1);
39
+ }
40
+
41
+ fs.mkdirSync(targetDir, { recursive: true });
42
+
43
+ const entries = fs.readdirSync(templateDir, { withFileTypes: true });
44
+
45
+ for (const entry of entries) {
46
+ const srcPath = path.join(templateDir, entry.name);
47
+ const destPath = path.join(
48
+ targetDir,
49
+ entry.name.replace("APP_NAME", appName)
50
+ );
51
+
52
+ if (entry.isDirectory()) {
53
+ copyDirRecursive(srcPath, destPath, appName);
54
+ } else {
55
+ let content = fs.readFileSync(srcPath, "utf8");
56
+ content = content.replace(/APP_NAME/g, appName);
57
+ fs.writeFileSync(destPath, content, "utf8");
58
+ }
59
+ }
60
+ }
61
+
62
+ function copyDirRecursive(srcDir, destDir, appName) {
63
+ fs.mkdirSync(destDir, { recursive: true });
64
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
65
+
66
+ for (const entry of entries) {
67
+ const srcPath = path.join(srcDir, entry.name);
68
+ const destPath = path.join(
69
+ destDir,
70
+ entry.name.replace("APP_NAME", appName)
71
+ );
72
+
73
+ if (entry.isDirectory()) {
74
+ copyDirRecursive(srcPath, destPath, appName);
75
+ } else {
76
+ let content = fs.readFileSync(srcPath, "utf8");
77
+ content = content.replace(/APP_NAME/g, appName);
78
+ fs.writeFileSync(destPath, content, "utf8");
79
+ }
80
+ }
81
+ }
82
+
83
+ program
84
+ .name("create-node-app")
85
+ .argument("<app-name>", "name of the new Node.js app")
86
+ .option(
87
+ "-d, --db <type>",
88
+ "database type (mongo, postgres, mysql, none)",
89
+ "mongo"
90
+ )
91
+ .action((appName, options) => {
92
+ const targetDir = path.resolve(process.cwd(), appName);
93
+
94
+ if (fs.existsSync(targetDir)) {
95
+ console.error(`Directory ${appName} already exists. Aborting.`);
96
+ process.exit(1);
97
+ }
98
+
99
+ const dbType = String(options.db || "mongo").toLowerCase();
100
+
101
+ console.log(`Creating Node.js app '${appName}'...`);
102
+ console.log(`Database selected: ${dbType}`);
103
+
104
+ copyTemplate(targetDir, appName, dbType);
105
+
106
+ console.log("Project created successfully!");
107
+ console.log(`\nNext steps:`);
108
+ console.log(` cd ${appName}`);
109
+ console.log(` npm install`);
110
+ console.log(` npm run dev`);
111
+ });
112
+
113
+ program.parse(process.argv);
114
+
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "build-node-app-personal",
3
+ "version": "1.0.0",
4
+ "description": "CLI to scaffold a Node.js app with basic setup and DB configuration",
5
+ "bin": {
6
+ "build-node-app": "bin/build-node-app.js"
7
+ },
8
+ "scripts": {
9
+ "start": "node bin/build-node-app.js",
10
+ "dev": "node bin/build-node-app.js"
11
+ },
12
+ "keywords": [
13
+ "cli",
14
+ "scaffold",
15
+ "node",
16
+ "generator"
17
+ ],
18
+ "author": "",
19
+ "license": "MIT",
20
+ "type": "module",
21
+ "dependencies": {
22
+ "commander": "^12.0.0"
23
+ }
24
+ }
package/template/.env ADDED
@@ -0,0 +1,3 @@
1
+ PORT=4000
2
+ MONGO_URI=mongodb://localhost:27017/APP_NAME
3
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "APP_NAME",
3
+ "version": "1.0.0",
4
+ "description": "Generated Node.js app",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "dev": "node server.js",
8
+ "start": "node server.js"
9
+ },
10
+ "type": "module",
11
+ "dependencies": {
12
+ "dotenv": "^16.4.0",
13
+ "express": "^4.19.0",
14
+ "mongoose": "^8.0.0"
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ import "dotenv/config";
2
+ import { createServer } from "./src/app.js";
3
+ import { connectDB } from "./src/config/db.js";
4
+
5
+ const port = process.env.PORT || 4000;
6
+
7
+ async function start() {
8
+ await connectDB();
9
+
10
+ const app = createServer();
11
+
12
+ app.listen(port, () => {
13
+ console.log(`Server running on http://localhost:${port}`);
14
+ });
15
+ }
16
+
17
+ start().catch((err) => {
18
+ console.error("Failed to start server:", err);
19
+ process.exit(1);
20
+ });
21
+
@@ -0,0 +1,30 @@
1
+ import express from "express";
2
+ import { userRouter } from "./routes/userRoutes.js";
3
+ import { requestLogger } from "./middleware/logger.js";
4
+ import { notFound } from "./middleware/notFound.js";
5
+ import { errorHandler } from "./middleware/errorHandler.js";
6
+
7
+ export function createServer() {
8
+ const app = express();
9
+
10
+ // Core middlewares
11
+ app.use(express.json());
12
+ app.use(requestLogger);
13
+
14
+ // Health check / root route
15
+ app.get("/", (req, res) => {
16
+ res.json({ message: "Welcome to APP_NAME API" });
17
+ });
18
+
19
+ // User CRUD routes
20
+ app.use("/api/users", userRouter);
21
+
22
+ // Not found + error handlers
23
+ app.use(notFound);
24
+ app.use(errorHandler);
25
+
26
+ return app;
27
+ }
28
+
29
+
30
+
@@ -0,0 +1,19 @@
1
+ import mongoose from "mongoose";
2
+
3
+ export async function connectDB() {
4
+ const uri = process.env.MONGO_URI;
5
+
6
+ if (!uri) {
7
+ console.warn("MONGO_URI not set. Skipping DB connection.");
8
+ return;
9
+ }
10
+
11
+ try {
12
+ await mongoose.connect(uri);
13
+ console.log("Connected to MongoDB");
14
+ } catch (err) {
15
+ console.error("MongoDB connection error:", err.message);
16
+ throw err;
17
+ }
18
+ }
19
+
@@ -0,0 +1,61 @@
1
+ import { User } from "../models/userModel.js";
2
+
3
+ export async function createUser(req, res, next) {
4
+ try {
5
+ const user = await User.create(req.body);
6
+ res.status(201).json(user);
7
+ } catch (err) {
8
+ next(err);
9
+ }
10
+ }
11
+
12
+ export async function getUsers(req, res, next) {
13
+ try {
14
+ const users = await User.find().lean();
15
+ res.json(users);
16
+ } catch (err) {
17
+ next(err);
18
+ }
19
+ }
20
+
21
+ export async function getUserById(req, res, next) {
22
+ try {
23
+ const user = await User.findById(req.params.id).lean();
24
+ if (!user) {
25
+ return res.status(404).json({ message: "User not found" });
26
+ }
27
+ res.json(user);
28
+ } catch (err) {
29
+ next(err);
30
+ }
31
+ }
32
+
33
+ export async function updateUser(req, res, next) {
34
+ try {
35
+ const user = await User.findByIdAndUpdate(req.params.id, req.body, {
36
+ new: true,
37
+ runValidators: true,
38
+ }).lean();
39
+
40
+ if (!user) {
41
+ return res.status(404).json({ message: "User not found" });
42
+ }
43
+
44
+ res.json(user);
45
+ } catch (err) {
46
+ next(err);
47
+ }
48
+ }
49
+
50
+ export async function deleteUser(req, res, next) {
51
+ try {
52
+ const user = await User.findByIdAndDelete(req.params.id).lean();
53
+ if (!user) {
54
+ return res.status(404).json({ message: "User not found" });
55
+ }
56
+ res.status(204).send();
57
+ } catch (err) {
58
+ next(err);
59
+ }
60
+ }
61
+
@@ -0,0 +1,12 @@
1
+ // Generic error-handling middleware
2
+ export function errorHandler(err, req, res, next) {
3
+ console.error("Error:", err);
4
+
5
+ const status = err.status || 500;
6
+ const message = err.message || "Internal Server Error";
7
+
8
+ res.status(status).json({
9
+ message,
10
+ });
11
+ }
12
+
@@ -0,0 +1,14 @@
1
+ // Basic request logger middleware
2
+ export function requestLogger(req, res, next) {
3
+ const start = Date.now();
4
+
5
+ res.on("finish", () => {
6
+ const duration = Date.now() - start;
7
+ console.log(
8
+ `${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`
9
+ );
10
+ });
11
+
12
+ next();
13
+ }
14
+
@@ -0,0 +1,8 @@
1
+ // 404 handler for unknown routes
2
+ export function notFound(req, res, next) {
3
+ res.status(404).json({
4
+ message: "Route not found",
5
+ path: req.originalUrl,
6
+ });
7
+ }
8
+
@@ -0,0 +1,13 @@
1
+ // Basic validation middleware for user payloads
2
+ export function validateUserBody(req, res, next) {
3
+ const { name, email } = req.body || {};
4
+
5
+ if (!name || !email) {
6
+ return res.status(400).json({
7
+ message: "Both 'name' and 'email' are required.",
8
+ });
9
+ }
10
+
11
+ next();
12
+ }
13
+
@@ -0,0 +1,24 @@
1
+ import mongoose from "mongoose";
2
+
3
+ const userSchema = new mongoose.Schema(
4
+ {
5
+ name: {
6
+ type: String,
7
+ required: true,
8
+ trim: true,
9
+ },
10
+ email: {
11
+ type: String,
12
+ required: true,
13
+ trim: true,
14
+ unique: true,
15
+ lowercase: true,
16
+ },
17
+ },
18
+ {
19
+ timestamps: true,
20
+ }
21
+ );
22
+
23
+ export const User = mongoose.models.User || mongoose.model("User", userSchema);
24
+
@@ -0,0 +1,27 @@
1
+ import express from "express";
2
+ import {
3
+ createUser,
4
+ getUsers,
5
+ getUserById,
6
+ updateUser,
7
+ deleteUser,
8
+ } from "../controllers/userController.js";
9
+ import { validateUserBody } from "../middleware/userMiddleware.js";
10
+
11
+ export const userRouter = express.Router();
12
+
13
+ // Create
14
+ userRouter.post("/", validateUserBody, createUser);
15
+
16
+ // Read all
17
+ userRouter.get("/", getUsers);
18
+
19
+ // Read one
20
+ userRouter.get("/:id", getUserById);
21
+
22
+ // Update
23
+ userRouter.put("/:id", validateUserBody, updateUser);
24
+
25
+ // Delete
26
+ userRouter.delete("/:id", deleteUser);
27
+
@@ -0,0 +1,7 @@
1
+ PORT=4000
2
+ MYSQL_HOST=localhost
3
+ MYSQL_PORT=3306
4
+ MYSQL_DATABASE=APP_NAME
5
+ MYSQL_USER=root
6
+ MYSQL_PASSWORD=password
7
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "APP_NAME",
3
+ "version": "1.0.0",
4
+ "description": "Generated Node.js app (MySQL user CRUD)",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "dev": "node server.js",
8
+ "start": "node server.js"
9
+ },
10
+ "type": "module",
11
+ "dependencies": {
12
+ "dotenv": "^16.4.0",
13
+ "express": "^4.19.0",
14
+ "mysql2": "^3.9.0"
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ import "dotenv/config";
2
+ import { createServer } from "./src/app.js";
3
+ import { connectDB } from "./src/config/db.js";
4
+
5
+ const port = process.env.PORT || 4000;
6
+
7
+ async function start() {
8
+ await connectDB();
9
+
10
+ const app = createServer();
11
+
12
+ app.listen(port, () => {
13
+ console.log(`Server running on http://localhost:${port}`);
14
+ });
15
+ }
16
+
17
+ start().catch((err) => {
18
+ console.error("Failed to start server:", err);
19
+ process.exit(1);
20
+ });
21
+
@@ -0,0 +1,28 @@
1
+ import express from "express";
2
+ import { userRouter } from "./routes/userRoutes.js";
3
+ import { requestLogger } from "./middleware/logger.js";
4
+ import { notFound } from "./middleware/notFound.js";
5
+ import { errorHandler } from "./middleware/errorHandler.js";
6
+
7
+ export function createServer() {
8
+ const app = express();
9
+
10
+ // Core middlewares
11
+ app.use(express.json());
12
+ app.use(requestLogger);
13
+
14
+ // Health check / root route
15
+ app.get("/", (req, res) => {
16
+ res.json({ message: "Welcome to APP_NAME API (MySQL)" });
17
+ });
18
+
19
+ // User CRUD routes
20
+ app.use("/api/users", userRouter);
21
+
22
+ // Not found + error handlers
23
+ app.use(notFound);
24
+ app.use(errorHandler);
25
+
26
+ return app;
27
+ }
28
+
@@ -0,0 +1,32 @@
1
+ import mysql from "mysql2/promise";
2
+
3
+ export let pool;
4
+
5
+ export async function connectDB() {
6
+ try {
7
+ pool = await mysql.createPool({
8
+ host: process.env.MYSQL_HOST || "localhost",
9
+ port: Number(process.env.MYSQL_PORT) || 3306,
10
+ database: process.env.MYSQL_DATABASE || "APP_NAME",
11
+ user: process.env.MYSQL_USER || "root",
12
+ password: process.env.MYSQL_PASSWORD || "password",
13
+ waitForConnections: true,
14
+ connectionLimit: 10,
15
+ });
16
+
17
+ await pool.query("SELECT 1");
18
+ await pool.query(`
19
+ CREATE TABLE IF NOT EXISTS users (
20
+ id INT AUTO_INCREMENT PRIMARY KEY,
21
+ name VARCHAR(255) NOT NULL,
22
+ email VARCHAR(255) NOT NULL UNIQUE
23
+ );
24
+ `);
25
+
26
+ console.log("Connected to MySQL");
27
+ } catch (err) {
28
+ console.error("MySQL connection error:", err.message);
29
+ throw err;
30
+ }
31
+ }
32
+
@@ -0,0 +1,62 @@
1
+ import {
2
+ createUser as createUserModel,
3
+ getAllUsers,
4
+ getUserById as getUserByIdModel,
5
+ updateUser as updateUserModel,
6
+ deleteUser as deleteUserModel,
7
+ } from "../models/userModel.js";
8
+
9
+ export async function createUser(req, res, next) {
10
+ try {
11
+ const user = await createUserModel(req.body);
12
+ res.status(201).json(user);
13
+ } catch (err) {
14
+ next(err);
15
+ }
16
+ }
17
+
18
+ export async function getUsers(req, res, next) {
19
+ try {
20
+ const users = await getAllUsers();
21
+ res.json(users);
22
+ } catch (err) {
23
+ next(err);
24
+ }
25
+ }
26
+
27
+ export async function getUserById(req, res, next) {
28
+ try {
29
+ const user = await getUserByIdModel(req.params.id);
30
+ if (!user) {
31
+ return res.status(404).json({ message: "User not found" });
32
+ }
33
+ res.json(user);
34
+ } catch (err) {
35
+ next(err);
36
+ }
37
+ }
38
+
39
+ export async function updateUser(req, res, next) {
40
+ try {
41
+ const user = await updateUserModel(req.params.id, req.body);
42
+ if (!user) {
43
+ return res.status(404).json({ message: "User not found" });
44
+ }
45
+ res.json(user);
46
+ } catch (err) {
47
+ next(err);
48
+ }
49
+ }
50
+
51
+ export async function deleteUser(req, res, next) {
52
+ try {
53
+ const success = await deleteUserModel(req.params.id);
54
+ if (!success) {
55
+ return res.status(404).json({ message: "User not found" });
56
+ }
57
+ res.status(204).send();
58
+ } catch (err) {
59
+ next(err);
60
+ }
61
+ }
62
+
@@ -0,0 +1,12 @@
1
+ // Generic error-handling middleware
2
+ export function errorHandler(err, req, res, next) {
3
+ console.error("Error:", err);
4
+
5
+ const status = err.status || 500;
6
+ const message = err.message || "Internal Server Error";
7
+
8
+ res.status(status).json({
9
+ message,
10
+ });
11
+ }
12
+
@@ -0,0 +1,14 @@
1
+ // Basic request logger middleware
2
+ export function requestLogger(req, res, next) {
3
+ const start = Date.now();
4
+
5
+ res.on("finish", () => {
6
+ const duration = Date.now() - start;
7
+ console.log(
8
+ `${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`
9
+ );
10
+ });
11
+
12
+ next();
13
+ }
14
+
@@ -0,0 +1,8 @@
1
+ // 404 handler for unknown routes
2
+ export function notFound(req, res, next) {
3
+ res.status(404).json({
4
+ message: "Route not found",
5
+ path: req.originalUrl,
6
+ });
7
+ }
8
+
@@ -0,0 +1,13 @@
1
+ // Basic validation middleware for user payloads
2
+ export function validateUserBody(req, res, next) {
3
+ const { name, email } = req.body || {};
4
+
5
+ if (!name || !email) {
6
+ return res.status(400).json({
7
+ message: "Both 'name' and 'email' are required.",
8
+ });
9
+ }
10
+
11
+ next();
12
+ }
13
+
@@ -0,0 +1,39 @@
1
+ import { pool } from "../config/db.js";
2
+
3
+ export async function createUser(data) {
4
+ const { name, email } = data;
5
+ const [result] = await pool.query(
6
+ "INSERT INTO users (name, email) VALUES (?, ?)",
7
+ [name, email]
8
+ );
9
+ const [rows] = await pool.query("SELECT * FROM users WHERE id = ?", [
10
+ result.insertId,
11
+ ]);
12
+ return rows[0];
13
+ }
14
+
15
+ export async function getAllUsers() {
16
+ const [rows] = await pool.query("SELECT * FROM users ORDER BY id");
17
+ return rows;
18
+ }
19
+
20
+ export async function getUserById(id) {
21
+ const [rows] = await pool.query("SELECT * FROM users WHERE id = ?", [id]);
22
+ return rows[0] || null;
23
+ }
24
+
25
+ export async function updateUser(id, updates) {
26
+ const { name, email } = updates;
27
+ await pool.query(
28
+ "UPDATE users SET name = ?, email = ? WHERE id = ?",
29
+ [name, email, id]
30
+ );
31
+ const [rows] = await pool.query("SELECT * FROM users WHERE id = ?", [id]);
32
+ return rows[0] || null;
33
+ }
34
+
35
+ export async function deleteUser(id) {
36
+ const [result] = await pool.query("DELETE FROM users WHERE id = ?", [id]);
37
+ return result.affectedRows > 0;
38
+ }
39
+
@@ -0,0 +1,27 @@
1
+ import express from "express";
2
+ import {
3
+ createUser,
4
+ getUsers,
5
+ getUserById,
6
+ updateUser,
7
+ deleteUser,
8
+ } from "../controllers/userController.js";
9
+ import { validateUserBody } from "../middleware/userMiddleware.js";
10
+
11
+ export const userRouter = express.Router();
12
+
13
+ // Create
14
+ userRouter.post("/", validateUserBody, createUser);
15
+
16
+ // Read all
17
+ userRouter.get("/", getUsers);
18
+
19
+ // Read one
20
+ userRouter.get("/:id", getUserById);
21
+
22
+ // Update
23
+ userRouter.put("/:id", validateUserBody, updateUser);
24
+
25
+ // Delete
26
+ userRouter.delete("/:id", deleteUser);
27
+
@@ -0,0 +1,2 @@
1
+ PORT=4000
2
+
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "APP_NAME",
3
+ "version": "1.0.0",
4
+ "description": "Generated Node.js app (no database, in-memory user store)",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "dev": "node server.js",
8
+ "start": "node server.js"
9
+ },
10
+ "type": "module",
11
+ "dependencies": {
12
+ "dotenv": "^16.4.0",
13
+ "express": "^4.19.0"
14
+ }
15
+ }
@@ -0,0 +1,18 @@
1
+ import "dotenv/config";
2
+ import { createServer } from "./src/app.js";
3
+
4
+ const port = process.env.PORT || 4000;
5
+
6
+ async function start() {
7
+ const app = createServer();
8
+
9
+ app.listen(port, () => {
10
+ console.log(`Server running on http://localhost:${port}`);
11
+ });
12
+ }
13
+
14
+ start().catch((err) => {
15
+ console.error("Failed to start server:", err);
16
+ process.exit(1);
17
+ });
18
+
@@ -0,0 +1,24 @@
1
+ import express from "express";
2
+ import { userRouter } from "./routes/userRoutes.js";
3
+ import { requestLogger } from "./middleware/logger.js";
4
+ import { notFound } from "./middleware/notFound.js";
5
+ import { errorHandler } from "./middleware/errorHandler.js";
6
+
7
+ export function createServer() {
8
+ const app = express();
9
+
10
+ app.use(express.json());
11
+ app.use(requestLogger);
12
+
13
+ app.get("/", (req, res) => {
14
+ res.json({ message: "Welcome to APP_NAME API (no database)" });
15
+ });
16
+
17
+ app.use("/api/users", userRouter);
18
+
19
+ app.use(notFound);
20
+ app.use(errorHandler);
21
+
22
+ return app;
23
+ }
24
+
@@ -0,0 +1,5 @@
1
+ // No-op DB config for --db none
2
+ export async function connectDB() {
3
+ console.log("No database selected. Using in-memory storage.");
4
+ }
5
+
@@ -0,0 +1,61 @@
1
+ import {
2
+ createUser as createUserModel,
3
+ getAllUsers,
4
+ getUserById as getUserByIdModel,
5
+ updateUser as updateUserModel,
6
+ deleteUser as deleteUserModel,
7
+ } from "../models/userModel.js";
8
+
9
+ export async function createUser(req, res, next) {
10
+ try {
11
+ const user = createUserModel(req.body);
12
+ res.status(201).json(user);
13
+ } catch (err) {
14
+ next(err);
15
+ }
16
+ }
17
+
18
+ export async function getUsers(req, res, next) {
19
+ try {
20
+ res.json(getAllUsers());
21
+ } catch (err) {
22
+ next(err);
23
+ }
24
+ }
25
+
26
+ export async function getUserById(req, res, next) {
27
+ try {
28
+ const user = getUserByIdModel(req.params.id);
29
+ if (!user) {
30
+ return res.status(404).json({ message: "User not found" });
31
+ }
32
+ res.json(user);
33
+ } catch (err) {
34
+ next(err);
35
+ }
36
+ }
37
+
38
+ export async function updateUser(req, res, next) {
39
+ try {
40
+ const user = updateUserModel(req.params.id, req.body);
41
+ if (!user) {
42
+ return res.status(404).json({ message: "User not found" });
43
+ }
44
+ res.json(user);
45
+ } catch (err) {
46
+ next(err);
47
+ }
48
+ }
49
+
50
+ export async function deleteUser(req, res, next) {
51
+ try {
52
+ const success = deleteUserModel(req.params.id);
53
+ if (!success) {
54
+ return res.status(404).json({ message: "User not found" });
55
+ }
56
+ res.status(204).send();
57
+ } catch (err) {
58
+ next(err);
59
+ }
60
+ }
61
+
@@ -0,0 +1,12 @@
1
+ // Generic error-handling middleware
2
+ export function errorHandler(err, req, res, next) {
3
+ console.error("Error:", err);
4
+
5
+ const status = err.status || 500;
6
+ const message = err.message || "Internal Server Error";
7
+
8
+ res.status(status).json({
9
+ message,
10
+ });
11
+ }
12
+
@@ -0,0 +1,14 @@
1
+ // Basic request logger middleware
2
+ export function requestLogger(req, res, next) {
3
+ const start = Date.now();
4
+
5
+ res.on("finish", () => {
6
+ const duration = Date.now() - start;
7
+ console.log(
8
+ `${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`
9
+ );
10
+ });
11
+
12
+ next();
13
+ }
14
+
@@ -0,0 +1,8 @@
1
+ // 404 handler for unknown routes
2
+ export function notFound(req, res, next) {
3
+ res.status(404).json({
4
+ message: "Route not found",
5
+ path: req.originalUrl,
6
+ });
7
+ }
8
+
@@ -0,0 +1,13 @@
1
+ // Basic validation middleware for user payloads
2
+ export function validateUserBody(req, res, next) {
3
+ const { name, email } = req.body || {};
4
+
5
+ if (!name || !email) {
6
+ return res.status(400).json({
7
+ message: "Both 'name' and 'email' are required.",
8
+ });
9
+ }
10
+
11
+ next();
12
+ }
13
+
@@ -0,0 +1,34 @@
1
+ // In-memory user "model" for apps generated with --db none
2
+
3
+ let users = [];
4
+ let nextId = 1;
5
+
6
+ export function createUser(data) {
7
+ const user = { id: String(nextId++), ...data };
8
+ users.push(user);
9
+ return user;
10
+ }
11
+
12
+ export function getAllUsers() {
13
+ return users;
14
+ }
15
+
16
+ export function getUserById(id) {
17
+ return users.find((u) => u.id === String(id)) || null;
18
+ }
19
+
20
+ export function updateUser(id, updates) {
21
+ const idx = users.findIndex((u) => u.id === String(id));
22
+ if (idx === -1) return null;
23
+
24
+ users[idx] = { ...users[idx], ...updates };
25
+ return users[idx];
26
+ }
27
+
28
+ export function deleteUser(id) {
29
+ const idx = users.findIndex((u) => u.id === String(id));
30
+ if (idx === -1) return false;
31
+ users.splice(idx, 1);
32
+ return true;
33
+ }
34
+
@@ -0,0 +1,27 @@
1
+ import express from "express";
2
+ import {
3
+ createUser,
4
+ getUsers,
5
+ getUserById,
6
+ updateUser,
7
+ deleteUser,
8
+ } from "../controllers/userController.js";
9
+ import { validateUserBody } from "../middleware/userMiddleware.js";
10
+
11
+ export const userRouter = express.Router();
12
+
13
+ // Create
14
+ userRouter.post("/", validateUserBody, createUser);
15
+
16
+ // Read all
17
+ userRouter.get("/", getUsers);
18
+
19
+ // Read one
20
+ userRouter.get("/:id", getUserById);
21
+
22
+ // Update
23
+ userRouter.put("/:id", validateUserBody, updateUser);
24
+
25
+ // Delete
26
+ userRouter.delete("/:id", deleteUser);
27
+
@@ -0,0 +1,7 @@
1
+ PORT=4000
2
+ PG_HOST=localhost
3
+ PG_PORT=5432
4
+ PG_DATABASE=APP_NAME
5
+ PG_USER=postgres
6
+ PG_PASSWORD=password
7
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "APP_NAME",
3
+ "version": "1.0.0",
4
+ "description": "Generated Node.js app (PostgreSQL user CRUD)",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "dev": "node server.js",
8
+ "start": "node server.js"
9
+ },
10
+ "type": "module",
11
+ "dependencies": {
12
+ "dotenv": "^16.4.0",
13
+ "express": "^4.19.0",
14
+ "pg": "^8.11.0"
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ import "dotenv/config";
2
+ import { createServer } from "./src/app.js";
3
+ import { connectDB } from "./src/config/db.js";
4
+
5
+ const port = process.env.PORT || 4000;
6
+
7
+ async function start() {
8
+ await connectDB();
9
+
10
+ const app = createServer();
11
+
12
+ app.listen(port, () => {
13
+ console.log(`Server running on http://localhost:${port}`);
14
+ });
15
+ }
16
+
17
+ start().catch((err) => {
18
+ console.error("Failed to start server:", err);
19
+ process.exit(1);
20
+ });
21
+
@@ -0,0 +1,28 @@
1
+ import express from "express";
2
+ import { userRouter } from "./routes/userRoutes.js";
3
+ import { requestLogger } from "./middleware/logger.js";
4
+ import { notFound } from "./middleware/notFound.js";
5
+ import { errorHandler } from "./middleware/errorHandler.js";
6
+
7
+ export function createServer() {
8
+ const app = express();
9
+
10
+ // Core middlewares
11
+ app.use(express.json());
12
+ app.use(requestLogger);
13
+
14
+ // Health check / root route
15
+ app.get("/", (req, res) => {
16
+ res.json({ message: "Welcome to APP_NAME API (PostgreSQL)" });
17
+ });
18
+
19
+ // User CRUD routes
20
+ app.use("/api/users", userRouter);
21
+
22
+ // Not found + error handlers
23
+ app.use(notFound);
24
+ app.use(errorHandler);
25
+
26
+ return app;
27
+ }
28
+
@@ -0,0 +1,29 @@
1
+ import pkg from "pg";
2
+
3
+ const { Pool } = pkg;
4
+
5
+ export const pool = new Pool({
6
+ host: process.env.PG_HOST || "localhost",
7
+ port: Number(process.env.PG_PORT) || 5432,
8
+ database: process.env.PG_DATABASE || "APP_NAME",
9
+ user: process.env.PG_USER || "postgres",
10
+ password: process.env.PG_PASSWORD || "password",
11
+ });
12
+
13
+ export async function connectDB() {
14
+ try {
15
+ await pool.query("SELECT 1");
16
+ await pool.query(`
17
+ CREATE TABLE IF NOT EXISTS users (
18
+ id SERIAL PRIMARY KEY,
19
+ name TEXT NOT NULL,
20
+ email TEXT NOT NULL UNIQUE
21
+ );
22
+ `);
23
+ console.log("Connected to PostgreSQL");
24
+ } catch (err) {
25
+ console.error("PostgreSQL connection error:", err.message);
26
+ throw err;
27
+ }
28
+ }
29
+
@@ -0,0 +1,62 @@
1
+ import {
2
+ createUser as createUserModel,
3
+ getAllUsers,
4
+ getUserById as getUserByIdModel,
5
+ updateUser as updateUserModel,
6
+ deleteUser as deleteUserModel,
7
+ } from "../models/userModel.js";
8
+
9
+ export async function createUser(req, res, next) {
10
+ try {
11
+ const user = await createUserModel(req.body);
12
+ res.status(201).json(user);
13
+ } catch (err) {
14
+ next(err);
15
+ }
16
+ }
17
+
18
+ export async function getUsers(req, res, next) {
19
+ try {
20
+ const users = await getAllUsers();
21
+ res.json(users);
22
+ } catch (err) {
23
+ next(err);
24
+ }
25
+ }
26
+
27
+ export async function getUserById(req, res, next) {
28
+ try {
29
+ const user = await getUserByIdModel(req.params.id);
30
+ if (!user) {
31
+ return res.status(404).json({ message: "User not found" });
32
+ }
33
+ res.json(user);
34
+ } catch (err) {
35
+ next(err);
36
+ }
37
+ }
38
+
39
+ export async function updateUser(req, res, next) {
40
+ try {
41
+ const user = await updateUserModel(req.params.id, req.body);
42
+ if (!user) {
43
+ return res.status(404).json({ message: "User not found" });
44
+ }
45
+ res.json(user);
46
+ } catch (err) {
47
+ next(err);
48
+ }
49
+ }
50
+
51
+ export async function deleteUser(req, res, next) {
52
+ try {
53
+ const success = await deleteUserModel(req.params.id);
54
+ if (!success) {
55
+ return res.status(404).json({ message: "User not found" });
56
+ }
57
+ res.status(204).send();
58
+ } catch (err) {
59
+ next(err);
60
+ }
61
+ }
62
+
@@ -0,0 +1,12 @@
1
+ // Generic error-handling middleware
2
+ export function errorHandler(err, req, res, next) {
3
+ console.error("Error:", err);
4
+
5
+ const status = err.status || 500;
6
+ const message = err.message || "Internal Server Error";
7
+
8
+ res.status(status).json({
9
+ message,
10
+ });
11
+ }
12
+
@@ -0,0 +1,14 @@
1
+ // Basic request logger middleware
2
+ export function requestLogger(req, res, next) {
3
+ const start = Date.now();
4
+
5
+ res.on("finish", () => {
6
+ const duration = Date.now() - start;
7
+ console.log(
8
+ `${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`
9
+ );
10
+ });
11
+
12
+ next();
13
+ }
14
+
@@ -0,0 +1,8 @@
1
+ // 404 handler for unknown routes
2
+ export function notFound(req, res, next) {
3
+ res.status(404).json({
4
+ message: "Route not found",
5
+ path: req.originalUrl,
6
+ });
7
+ }
8
+
@@ -0,0 +1,13 @@
1
+ // Basic validation middleware for user payloads
2
+ export function validateUserBody(req, res, next) {
3
+ const { name, email } = req.body || {};
4
+
5
+ if (!name || !email) {
6
+ return res.status(400).json({
7
+ message: "Both 'name' and 'email' are required.",
8
+ });
9
+ }
10
+
11
+ next();
12
+ }
13
+
@@ -0,0 +1,35 @@
1
+ import { pool } from "../config/db.js";
2
+
3
+ export async function createUser(data) {
4
+ const { name, email } = data;
5
+ const result = await pool.query(
6
+ "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
7
+ [name, email]
8
+ );
9
+ return result.rows[0];
10
+ }
11
+
12
+ export async function getAllUsers() {
13
+ const result = await pool.query("SELECT * FROM users ORDER BY id");
14
+ return result.rows;
15
+ }
16
+
17
+ export async function getUserById(id) {
18
+ const result = await pool.query("SELECT * FROM users WHERE id = $1", [id]);
19
+ return result.rows[0] || null;
20
+ }
21
+
22
+ export async function updateUser(id, updates) {
23
+ const { name, email } = updates;
24
+ const result = await pool.query(
25
+ "UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *",
26
+ [name, email, id]
27
+ );
28
+ return result.rows[0] || null;
29
+ }
30
+
31
+ export async function deleteUser(id) {
32
+ const result = await pool.query("DELETE FROM users WHERE id = $1", [id]);
33
+ return result.rowCount > 0;
34
+ }
35
+
@@ -0,0 +1,27 @@
1
+ import express from "express";
2
+ import {
3
+ createUser,
4
+ getUsers,
5
+ getUserById,
6
+ updateUser,
7
+ deleteUser,
8
+ } from "../controllers/userController.js";
9
+ import { validateUserBody } from "../middleware/userMiddleware.js";
10
+
11
+ export const userRouter = express.Router();
12
+
13
+ // Create
14
+ userRouter.post("/", validateUserBody, createUser);
15
+
16
+ // Read all
17
+ userRouter.get("/", getUsers);
18
+
19
+ // Read one
20
+ userRouter.get("/:id", getUserById);
21
+
22
+ // Update
23
+ userRouter.put("/:id", validateUserBody, updateUser);
24
+
25
+ // Delete
26
+ userRouter.delete("/:id", deleteUser);
27
+