Building a Full-Stack CRUD Application with Node.js and MongoDB

Building a full-stack CRUD (Create, Read, Update, Delete) application is a foundational skill for web developers. In this tutorial, we’ll create a complete application using Node.js for the backend and MongoDB for the database. This app will also include user login and logout functionalities using JSON Web Tokens (JWT).

Prerequisites

Before you begin, ensure you have the following:

  • Node.js installed on your system.
  • MongoDB installed locally or access to a MongoDB Atlas cluster.
  • A basic understanding of JavaScript and REST APIs.
  • A text editor like Visual Studio Code.


Step 1: Setting Up the Project

1.1 Initialize the Project

Open your terminal and create a new project directory:

mkdir fullstack-crud-nodejs-mongodb
cd fullstack-crud-nodejs-mongodb


Initialize a new Node.js project:

npm init -y

Install the required dependencies:

npm install express mongoose bcryptjs jsonwebtoken dotenv cors body-parser
npm install --save-dev nodemon


1.2 Project Structure

Create the following folder structure:

fullstack-crud-nodejs-mongodb/
|-- models/
|-- routes/
|-- controllers/
|-- config/
|-- .env
|-- server.js


Step 2: Setting Up the Backend


2.1 Configure Environment Variables

Create a .env file in the root directory:

PORT=5000
MONGO_URI=mongodb://localhost:27017/crud-app
JWT_SECRET=your_jwt_secret


2.2 Connect to MongoDB


Create a config/database.js file:

const mongoose = require('mongoose');

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGO_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log('MongoDB connected');
  } catch (err) {
    console.error(err.message);
    process.exit(1);
  }
};

module.exports = connectDB;


Update server.js to include the database connection:

require('dotenv').config();
const express = require('express');
const connectDB = require('./config/database');
const cors = require('cors');

const app = express();
connectDB();

app.use(cors());
app.use(express.json());

app.listen(process.env.PORT, () => {
  console.log(`Server running on port ${process.env.PORT}`);
});


2.3 Create the User Model

In the models/ folder, create User.js:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const UserSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
});

UserSchema.pre('save', async function (next) {
  if (!this.isModified('password')) return next();
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
  next();
});

module.exports = mongoose.model('User', UserSchema);


2.4 Create Authentication Routes

In the routes/ folder, create auth.js:

const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const User = require('../models/User');

const router = express.Router();

// Register
router.post('/register', async (req, res) => {
  const { username, email, password } = req.body;
  try {
    const newUser = new User({ username, email, password });
    await newUser.save();
    res.status(201).json({ message: 'User registered successfully' });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Login
router.post('/login', async (req, res) => {
  const { email, password } = req.body;
  try {
    const user = await User.findOne({ email });
    if (!user) return res.status(404).json({ message: 'User not found' });

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });

    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
    res.json({ token });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

module.exports = router;


Add this route to server.js:

const authRoutes = require('./routes/auth');
app.use('/api/auth', authRoutes);


2.5 Create CRUD Operations for a Resource

In the models/ folder, create Post.js:

const mongoose = require('mongoose');

const PostSchema = new mongoose.Schema({
  title: { type: String, required: true },
  content: { type: String, required: true },
  user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
});

module.exports = mongoose.model('Post', PostSchema);

 

In the routes/ folder, create posts.js:

const express = require('express');
const Post = require('../models/Post');
const router = express.Router();

// Create Post
router.post('/', async (req, res) => {
  const { title, content, userId } = req.body;
  try {
    const newPost = new Post({ title, content, user: userId });
    await newPost.save();
    res.status(201).json(newPost);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Read All Posts
router.get('/', async (req, res) => {
  try {
    const posts = await Post.find().populate('user', 'username email');
    res.json(posts);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Update Post
router.put('/:id', async (req, res) => {
  try {
    const updatedPost = await Post.findByIdAndUpdate(req.params.id, req.body, { new: true });
    res.json(updatedPost);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Delete Post
router.delete('/:id', async (req, res) => {
  try {
    await Post.findByIdAndDelete(req.params.id);
    res.json({ message: 'Post deleted successfully' });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

module.exports = router;


Add this route to server.js:

const postRoutes = require('./routes/posts');
app.use('/api/posts', postRoutes);


Step 3: Testing the API


Use a tool like Postman to test the following endpoints:

Register User: POST /api/auth/register

Login User: POST /api/auth/login

Create Post: POST /api/posts

Get All Posts: GET /api/posts

Update Post: PUT /api/posts/:id

Delete Post: DELETE /api/posts/:id

Hope this is helpful, and I apologize if there are any inaccuracies in the information provided.

Post a Comment for "Building a Full-Stack CRUD Application with Node.js and MongoDB"