If you need a source code for this tutorial you can get it here.
In our previous article, we completed the groundwork for the front-end of our CMS project. We established the main layout, incorporated fonts, and structured the client-side components. Now, it's time to shift our focus to the back-end, which will power our application.
Today, we'll dive into three crucial aspects of our Node.js project:
- Structuring our server-side codebase
- Establishing a connection to MongoDB
These steps will lay a solid foundation for our CMS's back-end functionality. As we outlined our plan then, let's jump right into the development process.
1. Structuring our server-side codebase
In the project setup process, we already created a server.js file with basic Express.js configurations to define and run our new server. However, it's not optimal to add all our code into a single server.js file, especially for large or complex projects. So in this article, we'll create a structure for our project, including folders to store our main server files, with our server.js acting as the root file. Let's break this down step-by-step, starting with routes:
In a Node.js project, routes define the endpoints of your application and specify how it should respond to client requests. They act as a map that guides incoming HTTP requests to the appropriate handler functions, allowing you to organize your application's functionality into logical sections.
To separate routes we need to create a "routes" folder in the root folder. Inside routes let's create a "users" folder that will store APIs and their controllers, it will be our typical structure and for each section, we will create a separate folder with its controlling files. users.router.js file will import the express router, and our future controller file (we will create it in a few moments later), and store a list of routes related to the user (registration, login, ext...). Also, we need to export usersRoutes for the main API.js file. Here is an example:
const express = require('express');
const usersController = require('./users.controller');
const usersRouter = express.Router();
usersRouter.post('/register', usersController.registerNewUser);
module.exports = usersRouter;
Okay, and controllers are responsible for handling the application's business logic and acting as an intermediary between the routes and the data models. They receive requests from the routes, process the data (often interacting with models), and send back the appropriate responses, thus separating the request-handling logic from the route definitions.
As we mentioned, we need to create a users.controller.js file, and this file will store functions that will interact with API requests, then with db (with Mongoose model in our case) and return some sort of data, or modify existing data in the DB.
const usersModel = require('../../models/users/users.model');
async function registerNewUser(req, res) {
const {name, password, email} = req.body;
try {
if (name, password, email) {
res.status(201).json({
status: 'success',
message: 'User created successfully',
})
}
} catch (error) {
console.log(error);
res.status(500).json({
status: 'error',
message: 'Internal server error'
});
}
}
module.exports = {
registerNewUser
}
Next, we will talk about models, models in a Node.js project represent the data structure of your application and typically correspond to collections in your database. They define the shape of the documents within a collection, including the fields and their data types, and often include methods for interacting with that data.
To store our models we need to create a "models" folder in the root, and inside models we will create a separate folder for each model type. For example, we will create a "users" folder that will store users' models and users' mongoose schema. And simple user model example, that will create new users in our MongoDB database:
const users = require('./users.mongo');
async function createNewUser(payload) {
try {
const newUser = await users.create(payload);
return newUser;
} catch (error) {
console.error('Error creating new user:', error);
throw error;
}
}
module.exports = {
createNewUser
}
Schema, our last structure part of Node js server. Mongoose schemas are blueprint definitions for MongoDB documents, specifying the structure of data for a particular collection. They allow you to define fields, validation rules, defaults, and other metadata for your models, providing a powerful way to enforce data consistency and integrity in your MongoDB databases.
We will store schemas with models in the same folders, so we simply need to create users.mongo.js, here is the code example:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
address: {
type: String,
default: ''
},
email: {
type: String,
required: [true, 'Please provide your email!'],
default: ''
},
password: {
type: String,
required: [true, 'Please provide your password!'],
default: ''
},
name: {
type: String,
default: ''
},
});
module.exports = mongoose.model('User', userSchema);
A schema is simply an example of a stored data structure or object. Great, now we can move on to more examples of practice.
2. Establishing a connection to MongoDB
Previously we prepared our Node js server structure and installed MongoDB on our local machine, but we still did not connect our server with Mongo, let's fix it.
First, we will create a new "services" folder in the root folder, and inside we will add a mongo.js file that will store all Mongo settings.
Inside Mongo.js file we need to import "mongoose" for using mongoose. Connection object that provides methods and properties for managing the database connection, such as connecting, disconnecting, and checking the connection status. We will create and export two functions to connect and disconnect with MongoDB. Okay let's check our whole settings file, and it will be more clear.
const mongoose = require('mongoose');
const MONGO_URL = "mongodb://0.0.0.0:27017/blog";
mongoose.connection.once('open', () => {
console.log('MongoDB connection ready!');
});
mongoose.connection.on('error', (err) => {
console.error(err);
});
async function mongoConnect() {
await mongoose.connect(MONGO_URL);
}
async function mongoDisconnect() {
await mongoose.disconnect();
}
module.exports = {
mongoConnect,
mongoDisconnect,
}
So, we call the connect function that will connect through MongoDB URL our database to our Node js server, then we use the connection.once function that will log a small message if the database was connected, and connection.on the function that will log error messages if such would appear.
We finished with mongo.js file, but we need to add a connection function to the server.js file so that when the server starts it will be also connected to our database.
We will create and call the startServer function, which will connect our server to the database and after that it will create a server, and listen to our 8443 port.
const http = require('http');
const app = require('./app');
const mongo = require('./services/mongo');
const PORT = 8443;
async function startServer() {
await mongo.mongoConnect();
const server = http.createServer(app);
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
})
}
startServer();
In conclusion, we've made significant progress in structuring our Node.js backend for our CMS project. We've covered three crucial aspects:
We established a folder structure for our server-side codebase, separating concerns into routes, controllers, models, and schemas. This organization will make our project more maintainable and scalable as it grows.
We created our first model and schema for users, laying the groundwork for user management in our CMS.
We set up the connection to MongoDB, ensuring our application can persistently store and retrieve data.
These steps have laid a solid foundation for our CMS's backend functionality. With this structure in place, we're now well-positioned to build out more features, add additional models, and create the robust API that will power our CMS.
In our next article, we'll dive deeper into creating more complex routes, implementing authentication, and expanding our data models. Stay tuned as we continue to build our full-stack CMS from the ground up!
If you need a source code for this tutorial you can get it here.
Found this post useful? ☕ A coffee-sized contribution goes a long way in keeping me inspired! Thank you)
Next step: "Building a Complete User Registration System with React and Node.js"
Top comments (0)