Topic 011: Code snippets for controllers, routes, services, models and app.js/server.js in Node.js
Sure! I’ll walk you through a basic Node.js application using Express, illustrating the flow of data through controllers, routes, services, and models, along with the setup in app.js
or server.js
.
app.js
/ server.js
This file is the entry point of the application. It sets up the server and integrates all the routes.
// app.js or server.js
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const port = 3000;
// Middleware
app.use(bodyParser.json());
// Routes
const userRoutes = require("./routes/userRoutes");
app.use("/users", userRoutes);
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
Routes define the endpoints of your application and map them to the corresponding controller functions.
// routes/userRoutes.js
const express = require("express");
const router = express.Router();
const userController = require("../controllers/userController");
router.get("/", userController.getAllUsers);
router.get("/:id", userController.getUserById);
router.post("/", userController.createUser);
module.exports = router;
Controllers handle the incoming requests, process them, and return responses. They often call services to perform business logic.
// controllers/userController.js
const userService = require("../services/userService");
exports.getAllUsers = async (req, res) => {
try {
const users = await userService.getAllUsers();
res.json(users);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
exports.getUserById = async (req, res) => {
try {
const user = await userService.getUserById(req.params.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
res.json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
exports.createUser = async (req, res) => {
try {
const user = await userService.createUser(req.body);
res.status(201).json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
Services contain the business logic of the application. They interact with the models to perform database operations.
// services/userService.js
const User = require("../models/userModel");
exports.getAllUsers = async () => {
return await User.find();
};
exports.getUserById = async (id) => {
return await User.findById(id);
};
exports.createUser = async (userData) => {
const user = new User(userData);
return await user.save();
};
Models define the schema of your data and handle interactions with the database. In this example, we’re using Mongoose for MongoDB.
// models/userModel.js
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
module.exports = mongoose.model("User", userSchema);
Server Setup (app.js
/ server.js
): The application starts by running the app.js
file. This sets up the Express server and integrates middleware like body-parser
to handle JSON requests. It then imports and uses the user routes.
Routing (routes/userRoutes.js
): When a request hits an endpoint (e.g., /users
), it is directed to the corresponding route handler defined in userRoutes.js
.
Controller (controllers/userController.js
): The route handler invokes the appropriate controller function (e.g., getAllUsers
). The controller’s responsibility is to handle the request and response objects. It may call a service function to perform the business logic.
Service (services/userService.js
): The service function performs the actual business logic. For example, getAllUsers
might retrieve all users from the database by calling methods on the user model.
Model (models/userModel.js
): The model defines the structure of the data and interacts with the database. For instance, in userModel.js
, Mongoose is used to define the schema and provide methods like find
and findById
.
This architecture separates concerns effectively:
This separation makes the application modular, easier to maintain, and scalable.
dbconfig.js
require("dotenv").config();
const mongoose = require("mongoose");
//ES7 method to connect with DB
const dbConnect = async () => {
try {
//const uri = process.env.MONGODB_URI;
const uri = "mongodb://localhost:27017/MERN_CRUD";
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
};
const conn = await mongoose.connect(uri, options);
console.log(`MongoDB database Connected : ${conn.connection.host}`);
} catch (error) {
console.log(`Error connecting to MongoDB : ${error}`);
}
};
module.exports = dbConnect;
/*
ES6 method to connect with DB
module.exports = () => {
const connection = mongoose
.connect(process.env.MONGODB_URI)
.then((result) => console.log(`MongoDB databse Connected : ${connect.connection.host}`))
.catch((error) => console.log(`Error connecting to MongoDB : ${error}`));
};
*/
userControllers.js
const express = require("express");
//users model
const Users = require("../model/usersModel");
// @route POST /api/users/
// @desc Create a user
// @access Public
exports.createUser = async (req, res) => {
try {
const newUser = new Users(req.body);
await newUser.save();
res.status(201).json(newUser);
} catch (error) {
res.status(400).json({ message: error.message });
}
};
// @route GET /api/users/
// @desc Get all users
// @access Public
exports.getAllUsers = async (req, res) => {
try {
const users = await Users.find();
res.json(users);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
// @route GET /api/users/:id
// @desc Get a specific user
// @access Public
exports.getUserById = async (req, res) => {
try {
const user = await Users.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
res.json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
// @route PUT /api/users/:id
// @desc Update a user
// @access Public
exports.updateUser = async (req, res) => {
try {
const updatedUser = await Users.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!updatedUser) {
return res.status(404).json({ message: "User not found" });
}
res.json(updatedUser);
} catch (error) {
res.status(400).json({ message: error.message });
}
};
// @route DELETE /api/users/:id
// @desc Delete a user
// @access Public
exports.deleteUser = async (req, res) => {
try {
const deletedUser = await Users.findByIdAndDelete(req.params.id);
if (!deletedUser) {
return res.status(404).json({ message: "User not found" });
}
res.json({ message: "User deleted successfully" });
} catch (error) {
res.status(500).json({ message: error.message });
}
};
defaultDB.js
const mongoose = require("mongoose");
const dbConnect = require("../config/dbconfig");
const userModel = require("../model/usersModel");
const initializeDB = async () => {
// Connect to the database
dbConnect();
// Check if there are any existing users
const existingUsers = await userModel.find();
// If no users exist, seed the database with default data
if (existingUsers.length === 0) {
try {
// Add three default users
const defaultUsers = [
{ name: "Alex", email: "alex@example.com", age: 30 },
{ name: "Mike", email: "mike@example.com", age: 25 },
{ name: "John", email: "johne@example.com", age: 35 },
];
// Insert the default users into the database
await userModel.insertMany(defaultUsers);
console.log("Default data seeded successfully");
} catch (error) {
console.error(`Error seeding default data: ${error.message}`);
}
}
};
module.exports = initializeDB;
usersModel.js
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: String,
email: String,
age: Number,
});
const userModel = mongoose.model("users", userSchema);
module.exports = userModel;
usersRoutes.js
const express = require("express");
const router = express.Router();
const usersController = require("../controllers/usersControllers");
// POST /api/users - Create a new user
router.post("/", usersController.createUser);
// GET /api/users - Get all users
router.get("/", usersController.getAllUsers);
// GET /api/users/:id - Get a single user by ID
router.get("/:id", usersController.getUserById);
// PUT /api/users/:id - Update a user by ID
router.put("/:id", usersController.updateUser);
// DELETE /api/users/:id - Delete a user by ID
router.delete("/:id", usersController.deleteUser);
module.exports = router;
app.js
const express = require("express");
const path = require("path");
const dbConnect = require("./config/dbconfig");
const app = express();
// database connection
dbConnect();
// Use hpp, xss, helmet, cors express-mogo-sanitize for better security
// Use serve-index to serves pages that contain directory listings for a given path.
// middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
// routes
app.use("/api/users", require("./routes/usersRoutes"));
module.exports = app;
/* Production
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendfile(path.resolve(__dirname, "client", "build", "index.html"));
});
}*/
server.js
const app = require("./app");
require("dotenv").config();
const initializeDB = require("./model/defaultDB");
// Initialize default database connection
initializeDB();
const PORT = process.env.PORT || 5000;
//making app to listen on port from .env file which is 8001
app.listen(PORT, () => {
console.log(`App is running on port ${PORT}`);
});