Best Node.js & Express.js Project Structure
Let's first learn what Node.js & Express.js is and why should you use it?
Node.js
Node.js is an open-source, cross-platform, back-end JavaScript runtime environment that runs on a JavaScript Engine and executes JavaScript code outside a web browser, which was designed to build scalable network applications.
Express.js
Express.js, or simply Express, is a back end web application framework for building RESTful APIs with Node.js, released as free and open-source software under the MIT License. It is designed for building web applications and APIs. It has been called the de facto standard server framework for Node.js.
Now that you have an idea about node.js and express.js lets create a basic project.
Let’s create a folder, navigate to it and run following command on terminal.
npm init -y
You will see a file called package.json after execution of the command.
Now create a file called server.js in the same folder as package.json
To start working on it lets install few dependencies that will help you setup your server.
npm install express cors mongoose nodemon moment
Now once they are installed, you’ll be able to see them in package.json file as dependencies.
Next, add an initial code in your server.js file.
const express = require("express");const app = express();const bodyParser = require("body-parser");var cors = require("cors");app.use(bodyParser.urlencoded());app.use(bodyParser.json());app.use(cors());app.use((_, res) =>{res.send({message: 'Not found!'})});app.listen(5000, (req, res)=>{console.log("Server is listening on port 5000");})
Now before starting and testing your server add a run script in package.json.
{"name": "backend","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "nodemon server.js"},"keywords": [],"author": "","license": "ISC","dependencies": {"cors": "^2.8.5","express": "^4.18.1","mongoose": "^6.6.3","nodemon": "^2.0.20"}}
Now once it’s added let's run our server using
npm start
You can now see “Server is listening on port 5000” on your console.
Since our basic setup is done let’s move on to structuring our project.
Project Structure
Our project will be divided into 3 major folders as follows:
1. Controllers
2. Routes
3. Models
Let's understand it first.
Controllers
Our controllers folder will contain the main logic of each function. You will understand it more clearly as you read through this blog.
Routes
The routes folder will handle all the routes of our APIs. It will contain server files and a main file called index.js
Models
In this tutorial we are working on MongoDB. So, the models folder will contain all the models and schema of our MongoDB database.
Now that we know the basic folder structure, we will create then as stated above.
We will added another folder called helpers. It is not required but for our sake of simplicity and organization I will put all the miscellaneous file in it. For example, mongoose connection and etc.
I will add a file called mongoose-connection in our helpers foler and write the following code in it.
var mongoose = require("mongoose");const mongoAtlasUri = `mongodb://localhost:27017/basic`function mongooseConnection(){try {// Connect to the MongoDB clustermongoose.connect(mongoAtlasUri,{ useNewUrlParser: true, useUnifiedTopology: true },() => console.log("Mongoose is connected"),);} catch (e) {console.log("could not connect");}const dbConnection = mongoose.connection;dbConnection.on("error", (err) => console.log(`Connection error ${err}`));dbConnection.once("open", () => console.log("Connected to DB!"));}module.exports = mongooseConnection;
Now once create, we will import it in our main file i.e., server.js
const express = require("express");const app = express();const bodyParser = require("body-parser");var cors = require("cors");const mongooseConnection = require("./helpers/mongoose-connection");app.use(bodyParser.urlencoded());app.use(bodyParser.json());app.use(cors());app.use((_, res) =>{res.send({message: 'Not found!'})});mongooseConnection();app.listen(5000, (req, res)=>{console.log("Server is listening on port 5000");})
Now we will add a mongoose model in our models folder. We will name the file as “user.js” as it will contain user model.
const mongoose = require('mongoose');const { Schema } = mongoose;const userSchema = new mongoose.Schema({email: {type: String,unique: true,required: true},password: {type: String,required: true},username: {type: String},creation_date: {type: String}})module.exports = mongoose.model('User', userSchema);
Let’s now create a file called authController in our controllers folder. This file will contain all the logic for user registration and login.
const User = require("../models/user");const moment = require("moment");const login = (req, res) =>{User.find({ email: req.body.email}, function (err, docs) {if (err){console.log(err);}else{if(docs.length>0){if(docs[0].password==req.body.password){res.status(200).json({ status: "success" })}else{res.send("Invalid Credentials!");}}else{res.send("Invalid Credentials!");}}});}const register = async (req, res)=>{try {const user = await new User({email: req.body.email,password: req.body.password,username: req.body.username,creation_date: moment().format("MMMM Do YYYY, h:mm:ss a")})await user.save()res.status(200).json({ message: 'added!' })} catch (err) {console.log(err)if(err.code=='11000'){res.send('User Already Exists!');}else{res.send({ status: 'err', message: err });}}}module.exports = {login,register}
Now that might be little confusing but let’s understand the code step by step.
1. We have first imported the user model that was in models folder we create earlier.
2. Then we imported a package called moment. It will be used for getting current date.
3. We create a function called login. It will handle user login logic.
4. Login function is checking either the entered email is in database then matching the password and sending a response back to the client.
5. Next we have a register function. It is adding data to our db that was received from client-side.
(Please note this is very basic logic and passwords should not be stored as plain text in db)
6. Lastly, we exported login, and register function so that we can access it from other files as well.
Now since we have made a controller for authentication, we cannot use it until we create a route for it. Lets create a file called authRoutes.js in our routes folder.
const express = require("express");const authController = require("../controllers/authController")const authRouter = express.Router();authRouter.route("/login").post(authController.login);authRouter.route("/register").post(authController.register);module.exports = authRouter;
Now in this file we first initialized express and express router and imported the authController that we just created in controllers folder.
Next, we created a route “/login”, that will be a a post route and linked to login function of authController.
authRouter.route("/login").post(authController.login);
Syntax:
router_name.route("/route").post/get/put/patch/delete(imported_controller_name.function_name);
We have done the same for registration function on “/register” path and exported authRouter.
Currently, our project have only one routes for authentication controller but as it will have more route will need to organize it. For that we will create a file called index.js on routes folder and write the the below code.
const { Router: expressRouter } = require("express");const router = expressRouter();// auth routesconst authRouter = require("./authRoutes");router.use("/auth", authRouter);module.exports = router;
Here we have again imported express router. Next we imported the authRouter and assign the main path for it i.e., “/auth”. and lastly, we exported router.
Now the last and final step. We will import our main router in our main file “server.js” and initializing the entry point of our server “/api”.
You can now test “http://localhost:5000/api/auth/login” for login, and “http://localhost:5000/register” to register a user.
Note: Please make sure you already have node environment with related dependencies and a local mongodb setup.
GitHub Repo for this article: https://github.com/MuqtadirBillah/node-express-basic-structure.git
Now you know one of the best project structure for node.js and express.js based server.
Follow me for more interesting tips and tricks at Musab Abbasi — Medium
You can also find me on LinkedIn and Github