Creating an Express CRUD REST API with a full MVC system and a Mongoose database involves several steps. Here’s a comprehensive guide to set it up, including an explanation of the plugins used and the overall app structure.
Plugins and Packages Used
- Express: A web application framework for Node.js, designed for building web applications and APIs.
- Mongoose: An Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data and provides schema validation.
- Nodemon: A utility that monitors for any changes in your source and automatically restarts your server.
- Dotenv: A module to load environment variables from a
.env
file intoprocess.env
. - Body-Parser: Middleware to parse incoming request bodies in a middleware before your handlers, available under the
req.body
property. - Cors: Middleware to enable Cross-Origin Resource Sharing.
App Structure
project
│ .env
│ .gitignore
│ package.json
│ server.js
│
└───config
│ │ db.js
│
└───controllers
│ │ userController.js
│
└───models
│ │ userModel.js
│
└───routes
│ │ userRoutes.js
│
└───middleware
│ errorMiddleware.js
Step-by-Step Implementation
Step 1: Initialize the Project
mkdir project # Create project directory
cd project # Navigate to project directory
npm init -y # Initialize a new Node.js project with default settings
npm install express mongoose nodemon dotenv body-parser cors # Install necessary packages
Step 2: Setup .env
File
Create a .env
file in the root of your project:
PORT=3000 # Port number for the server
MONGO_URI=your_mongo_db_connection_string # MongoDB connection string
Step 3: Create server.js
Create server.js
in the root directory:
const express = require('express'); // Import express
const mongoose = require('mongoose'); // Import mongoose
const bodyParser = require('body-parser'); // Import body-parser for parsing request bodies
const cors = require('cors'); // Import cors for handling Cross-Origin Resource Sharing
const dotenv = require('dotenv'); // Import dotenv for environment variables
const userRoutes = require('./routes/userRoutes'); // Import user routes
const errorMiddleware = require('./middleware/errorMiddleware'); // Import error middleware
dotenv.config(); // Load environment variables
const app = express(); // Initialize express app
// Middleware setup
app.use(bodyParser.json()); // Parse JSON bodies
app.use(cors()); // Enable CORS
app.use('/api/users', userRoutes); // Use user routes
app.use(errorMiddleware); // Use error middleware
const PORT = process.env.PORT || 5000; // Define the port
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }) // Connect to MongoDB
.then(() => {
app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); // Start the server
})
.catch(err => console.error(err)); // Handle connection errors
Step 4: Setup Database Configuration
Create config/db.js
:
const mongoose = require('mongoose'); // Import mongoose
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true, // Use new URL parser
useUnifiedTopology: true, // Use unified topology
});
console.log('MongoDB connected...'); // Log successful connection
} catch (err) {
console.error(err.message); // Log connection errors
process.exit(1); // Exit process with failure
}
};
module.exports = connectDB; // Export the connection function
Step 5: Create Mongoose Model
Create models/userModel.js
:
const mongoose = require('mongoose'); // Import mongoose
const userSchema = new mongoose.Schema({ // Define user schema
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
}, {
timestamps: true, // Add createdAt and updatedAt fields
});
const User = mongoose.model('User', userSchema); // Create user model
module.exports = User; // Export user model
Step 6: Create Controllers
Create controllers/userController.js
:
const User = require('../models/userModel'); // Import user model
// Get all users
const getUsers = async (req, res) => {
try {
const users = await User.find(); // Find all users
res.json(users); // Return users in JSON format
} catch (err) {
res.status(500).json({ message: err.message }); // Handle errors
}
};
// Get a single user
const getUser = async (req, res) => {
try {
const user = await User.findById(req.params.id); // Find user by ID
if (!user) return res.status(404).json({ message: 'User not found' }); // Handle user not found
res.json(user); // Return user in JSON format
} catch (err) {
res.status(500).json({ message: err.message }); // Handle errors
}
};
// Create a new user
const createUser = async (req, res) => {
const user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password,
});
try {
const newUser = await user.save(); // Save new user
res.status(201).json(newUser); // Return new user in JSON format
} catch (err) {
res.status(400).json({ message: err.message }); // Handle errors
}
};
// Update a user
const updateUser = async (req, res) => {
try {
const user = await User.findById(req.params.id); // Find user by ID
if (!user) return res.status(404).json({ message: 'User not found' }); // Handle user not found
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
user.password = req.body.password || user.password;
const updatedUser = await user.save(); // Save updated user
res.json(updatedUser); // Return updated user in JSON format
} catch (err) {
res.status(400).json({ message: err.message }); // Handle errors
}
};
// Delete a user
const deleteUser = async (req, res) => {
try {
const user = await User.findById(req.params.id); // Find user by ID
if (!user) return res.status(404).json({ message: 'User not found' }); // Handle user not found
await user.remove(); // Remove user
res.json({ message: 'User removed' }); // Return success message
} catch (err) {
res.status(500).json({ message: err.message }); // Handle errors
}
};
module.exports = {
getUsers,
getUser,
createUser,
updateUser,
deleteUser,
}; // Export all controller functions
Step 7: Create Routes
Create routes/userRoutes.js
:
const express = require('express'); // Import express
const {
getUsers,
getUser,
createUser,
updateUser,
deleteUser,
} = require('../controllers/userController'); // Import controller functions
const router = express.Router(); // Create router
router.route('/')
.get(getUsers) // Route to get all users
.post(createUser); // Route to create a user
router.route('/:id')
.get(getUser) // Route to get a user by ID
.put(updateUser) // Route to update a user by ID
.delete(deleteUser); // Route to delete a user by ID
module.exports = router; // Export router
Step 8: Create Error Middleware
Create middleware/errorMiddleware.js
:
const errorMiddleware = (err, req, res, next) => {
const statusCode = res.statusCode !== 200 ? res.statusCode : 500; // Determine status code
res.status(statusCode);
res.json({
message: err.message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack, // Show stack trace only in development
});
};
module.exports = errorMiddleware; // Export error middleware
Step 9: Run the Server
Add a start script in package.json
:
"scripts": {
"start": "node server.js", // Script to start the server
"dev": "nodemon server.js" // Script to start the server with nodemon
}
Run the server:
npm run dev # Start the server in development mode
Diagram of the App Structure
project
│
├── .env # Environment variables
├── .gitignore # Git ignore file
├── package.json # Project metadata and dependencies
├── server.js # Entry point of the application
│
├── config # Configuration files
│ └── db.js # Database configuration
│
├── controllers # Controller files
│ └── userController.js
│
├── models # Mongoose models
│ └── userModel.js
│
├── routes # Route handlers
│ └── userRoutes.js
│
└── middleware # Custom middleware
└── errorMiddleware.js
This structure provides a modular approach to developing an Express application with a clear separation of concerns, making the app scalable and maintainable.
Postman Setup
Postman is a popular tool to test APIs. You can set up collections and environment variables to easily test your endpoints.
- Install Postman: Download and install Postman from here.
- Create a new collection: Click on “New” and then “Collection”. Name your collection (e.g., “User API”).
- Add requests: For each endpoint (e.g., GET /api/users, POST /api/users, etc.), create a new request inside your collection.
Postman Collection Setup
- Create Collection: In Postman, create a new collection named “User API”.
- Create Requests:
- GET /api/users:
- Method: GET
- URL:
http://localhost:3000/api/users
- POST /api/users:
- Method: POST
- URL:
http://localhost:3000/api/users
- Body: raw JSON
- GET /api/users:
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123"
}
- GET /api/users/:id:
- Method: GET
- URL:
http://localhost:3000/api/users/{{id}}
- (Replace
{{id}}
with a valid user ID)
- PUT /api/users/:id:
- Method: PUT
- URL:
http://localhost:3000/api/users/{{id}}
- Body: raw JSON
{
"name": "Jane Doe",
"email": "jane@example.com",
"password": "newpassword123"
}
- DELETE /api/users/:id:
- Method: DELETE
- URL:
http://localhost:3000/api/users/{{id}}
- (Replace
{{id}}
with a valid user ID)
Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.