DEV Community

Cover image for Building a Full-Stack CRUD Application with Express.js, MySQL, and Sequelize
FredAbod
FredAbod

Posted on

1

Building a Full-Stack CRUD Application with Express.js, MySQL, and Sequelize

Building a Full-Stack CRUD Application with Express.js, MySQL, and Sequelize

Introduction to MySQL and Sequelize ORM: A Complete Guide for Node.js Developers

In today's data-driven world, building robust database applications is essential for developers. MySQL remains one of the most popular relational database systems, and Sequelize provides an elegant Node.js ORM to interact with it. In this comprehensive tutorial, we'll build a complete CRUD (Create, Read, Update, Delete) application using Express.js, MySQL, and Sequelize from scratch.

Prerequisites

  • Node.js and npm installed on your system
  • MySQL installed and running
  • Basic understanding of JavaScript and Express.js
  • A cup of coffee (coding is always better with caffeine)

Let's dive into building our application!

Dive In

Setting Up MySQL for Our Project

Before we start coding, you'll need MySQL installed and running on your system.

Step 1: Install MySQL

If you haven't installed MySQL yet, download it from the official website and follow the installation instructions for your operating system.

Step 2: Create a Database

Open your MySQL terminal or MySQL Workbench and run:

CREATE DATABASE crud_db;
Enter fullscreen mode Exit fullscreen mode

That's it! Sequelize will handle creating our tables automatically.

Building Our Application Step by Step

Step 1: Initialize Your Node.js Project

Create a new directory and initialize a Node.js project:

mkdir sequelize-crud
cd sequelize-crud
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Required Dependencies

npm install express mysql2 sequelize dotenv
npm install --save-dev nodemon
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Environment Variables

Create a .env file to store your database credentials:

DB_NAME=crud_db
DB_USER=root
DB_PASSWORD=1234Asdf?
DB_HOST=localhost
DB_DIALECT=mysql
PORT=3500
Enter fullscreen mode Exit fullscreen mode

Step 4: Set Up Sequelize

Create a directory for configuration files:

mkdir config
Enter fullscreen mode Exit fullscreen mode

Now let's create the Sequelize configuration file. This file will handle connecting to the MySQL database and setting up the Sequelize instance.

Create config/database.js:

const { Sequelize } = require('sequelize');
require('dotenv').config();

const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    host: process.env.DB_HOST,
    dialect: process.env.DB_DIALECT,
    logging: false,
  }
);

const connectDB = async () => {
  try {
    await sequelize.authenticate();
    console.log('Database connection has been established successfully.');
    await sequelize.sync({ alter: true });
    console.log('All models were synchronized successfully.');
  } catch (error) {
    console.error('Unable to connect to the database:', error);
    process.exit(1);
  }
};

module.exports = { sequelize, connectDB };
Enter fullscreen mode Exit fullscreen mode

Step 5: Define Models

Create a directory for models:

mkdir models
Enter fullscreen mode Exit fullscreen mode

Create models/User.js:

const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/database');

const User = sequelize.define('User', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  name: {
    type: DataTypes.STRING,
    allowNull: false,
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true,
    validate: {
      isEmail: true,
    },
  },
  age: {
    type: DataTypes.INTEGER,
    allowNull: true,
  }
}, {
  tableName: 'users',
  timestamps: true,
});

module.exports = User;
Enter fullscreen mode Exit fullscreen mode

Step 6: Create Controllers

Create a directory for controllers:

mkdir controllers
Enter fullscreen mode Exit fullscreen mode

Create controllers/userController.js:

const User = require('../models/user');

// Create a new user
exports.createUser = async (req, res) => {
  try {
    const { name, email, age } = req.body;

    const user = await User.create({
      name,
      email,
      age
    });

    res.status(201).json({
      success: true,
      data: user
    });
  } catch (error) {
    res.status(400).json({
      success: false,
      error: error.message
    });
  }
};

// Get all users
exports.getAllUsers = async (req, res) => {
  try {
    const users = await User.findAll();

    res.status(200).json({
      success: true,
      count: users.length,
      data: users
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
};

// Get a single user by ID
exports.getUserById = async (req, res) => {
  try {
    const user = await User.findByPk(req.params.id);

    if (!user) {
      return res.status(404).json({
        success: false,
        error: 'User not found'
      });
    }

    res.status(200).json({
      success: true,
      data: user
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
};

// Update a user
exports.updateUser = async (req, res) => {
  try {
    const user = await User.findByPk(req.params.id);

    if (!user) {
      return res.status(404).json({
        success: false,
        error: 'User not found'
      });
    }

    const { name, email, age } = req.body;

    await user.update({
      name: name || user.name,
      email: email || user.email,
      age: age || user.age
    });

    res.status(200).json({
      success: true,
      data: user
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
};

// Delete a user
exports.deleteUser = async (req, res) => {
  try {
    const user = await User.findByPk(req.params.id);

    if (!user) {
      return res.status(404).json({
        success: false,
        error: 'User not found'
      });
    }

    await user.destroy();

    res.status(200).json({
      success: true,
      data: {}
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
};
Enter fullscreen mode Exit fullscreen mode

Step 7: Set Up Routes

Create a directory for routes:

mkdir routes
Enter fullscreen mode Exit fullscreen mode

Create routes/userRoutes.js:

const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

// Create a new user
router.post('/', userController.createUser);

// Get all users
router.get('/', userController.getAllUsers);

// Get a single user
router.get('/:id', userController.getUserById);

// Update a user
router.put('/:id', userController.updateUser);

// Delete a user
router.delete('/:id', userController.deleteUser);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Step 8: Create the Express Server

Create server.js:

const express = require('express');
const { connectDB } = require('./config/database');
const userRoutes = require('./routes/userRoutes');
require('dotenv').config();

// Initialize Express app
const app = express();

// Connect to database
connectDB();

// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.use('/api/users', userRoutes);

// Home route
app.get('/', (req, res) => {
  res.send('Welcome to User CRUD API with Express, MySQL, and Sequelize');
});

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Step 9: Run the Application

Start the application using nodemon:

npx nodemon server.js
Enter fullscreen mode Exit fullscreen mode

Your CRUD application is now up and running! You can use tools like Postman to test the API endpoints.

Folder Structure

Here's the final folder structure of our project:

sequelize-crud/
├── config/
│   └── database.js
├── controllers/
│   └── userController.js
├── models/
│   └── User.js
├── routes/
│   └── userRoutes.js
├── .env
├── package.json
├── server.js
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this tutorial, we built a full-stack CRUD application using Express.js, MySQL, and Sequelize. We covered setting up the project, defining models, creating controllers, and setting up routes. With this foundation, you can expand the application further by adding authentication, validation, and more features.
Don't forget to drop a like ❤️😉❤️
Happy coding!

Happy Coding

Top comments (0)