CRUD Tutorial using Node JS, Express, React JS, and MySQL (Full-Stack)

CRUD Tutorial using Node JS, Express, React JS, and MySQL (Full-Stack)

In this tutorial you will learn how to build a full stack CRUD application using node.js, express, MySQL, and React JS.

Not only that,

In this tutorial you will also learn to use Bulma CSS to style the frontend.

Thus, the application that is built becomes more user friendly with an elegant and responsive user interface (UI).

This is not a tutorial for beginners,

If you are a newbie to node.js express, I suggest you first learn the “Express Js Tutorial For Beginners”.

And if you are new to React JS, I suggest you first learn the “React Js Tutorial For Beginners”.

Let's get started.

#1. Install: Express, MySQL2, Nodemon, and Cors

Create a folder on your computer, here I named it “fullstack”.

If you create a folder with the same name, that's even better.

You are free to create it anywhere, either in C, D, or on the Desktop.

Then open the "fullstack" folder using the code editor, here I use Visual Studio Code.

I also suggest you to use Visual Studio Code.

You can download Visual Studio Code at the following link, then install it on your computer:

https://code.visualstudio.com/

After the "fullstack" folder is opened using Visual Studio Code, create a sub folder named "backend" inside the "fullstack" folder.

Next, open a terminal in Visual Studio Code on the menu bar terminal => new terminal.

Then, go to the “backend” folder by typing the following command in the terminal:

cd backend

After that, type the following command in the terminal to create a “package.json” file:

npm init -y

Next, install express, mysql2, sequelize and cors by typing the following command in the terminal:

npm install express mysql2 sequelize cors

Next, install nodemon as a development dependency by typing the following command in the terminal:

npm install --save-dev nodemon

Next, add the following code to the “package.json” file:

"type": "module",

So the file "package.json" looks like the following:

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "mysql2": "^2.3.0",
    "sequelize": "^6.6.5"
  },
  "devDependencies": {
    "nodemon": "^2.0.12"
  }
}

This is so that we can use ES6 Module Syntax to export and import modules.

#2. Create database and table

To be able to use MySQL, you need to install XAMPP, WAMP, MAMP, or similar software.

In this tutorial, I'm using XAMPP.

Then create a new database in MySQL, you can use tools such as SQLyog, PHPMyAdmin or similar tools.

Here I create a database with the name "mern_db".

If you create a database with the same name, that's even better.

To create a database in MySQL, it can be done by executing the following query:

CREATE DATABASE mern_db;

The SQL command above will create a database with the name "mern_db".

Next, create a table in the database “mern_db”.

Here I create a table with the name "products".

If you create a table with the same name, that's even better. 

To create a "products" table, it can be done by executing the following SQL command:

CREATE TABLE products(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
price DOUBLE,
createdAt DATE,
updatedAt DATE 
)ENGINE=INNODB;

The SQL command above will create a table named "products" with fields: id, title, price, createdAt, and updatedAt.

Sequelize requires you to have fields: id, createdAt, and updatedAt.

If you do not have that field, there will be an error.

 

#3. Application Structure

To make the application more structured neatly, we will apply the MVC (Model-View-Controllers) pattern.

Create “config”, “controllers”, “models”, and “routes” folders in the “backend” folder.

Then create a “database.js” file in the “config” folder, create a “Products.js” file in the “controllers” folder, create a “productModel.js” file in the “models” folder, create a “index.js” file in the “routes” folder, and create the “index.js” file in the “backend” folder.

Look at the following picture for more details:

img

#4. Connect to Database

Open the "database.js" file in the "config" folder, then type the following code:

import { Sequelize } from "sequelize";

const db = new Sequelize('mern_db', 'root', '', {
    host: "localhost",
    dialect: "mysql"
});

export default db;

 

#5. Models

Open the model file "productModel.js" which is in the "models" folder, then type the following code:

import { Sequelize } from "sequelize";
import db from "../config/database.js";

const { DataTypes } = Sequelize;

const Product = db.define('products',{
    title:{
        type: DataTypes.STRING
    },
    price:{
        type: DataTypes.DOUBLE
    }
},{
    freezeTableName: true
});

export default Product;

 

#6. Controllers

Open the controller file "Products.js" which is in the "controllers" folder, then type the following code:

import Product from "../models/productModel.js";

export const getAllProducts = async (req, res) => {
    try {
        const products = await Product.findAll();
        res.json(products);
    } catch (error) {
        res.json({ message: error.message });
    }  
}

export const getProductById = async (req, res) => {
    try {
        const product = await Product.findAll({
            where: {
                id: req.params.id
            }
        });
        res.json(product[0]);
    } catch (error) {
        res.json({ message: error.message });
    }  
}

export const createProduct = async (req, res) => {
    try {
        await Product.create(req.body);
        res.json({
            "message": "Product Created"
        });
    } catch (error) {
        res.json({ message: error.message });
    }  
}

export const updateProduct = async (req, res) => {
    try {
        await Product.update(req.body, {
            where: {
                id: req.params.id
            }
        });
        res.json({
            "message": "Product Updated"
        });
    } catch (error) {
        res.json({ message: error.message });
    }  
}

export const deleteProduct = async (req, res) => {
    try {
        await Product.destroy({
            where: {
                id: req.params.id
            }
        });
        res.json({
            "message": "Product Deleted"
        });
    } catch (error) {
        res.json({ message: error.message });
    }  
}

 

#7. Routes

Open the “index.js” file located in the “routes” folder, then type the following code:

import express from "express";

import { 
    getAllProducts,
    createProduct,
    getProductById,
    updateProduct,
    deleteProduct
} from "../controllers/Products.js";

const router = express.Router();

router.get('/', getAllProducts);
router.get('/:id', getProductById);
router.post('/', createProduct);
router.patch('/:id', updateProduct);
router.delete('/:id', deleteProduct);

export default router;

 

#8. Entry Point

Open the “index.js” file located in the “backend” folder, then type the following code:

import express from "express";
import db from "./config/database.js";
import productRoutes from "./routes/index.js";
import cors from "cors";

const app = express();

try {
    await db.authenticate();
    console.log('Database connected...');
} catch (error) {
    console.error('Connection error:', error);
}

app.use(cors());
app.use(express.json());
app.use('/products', productRoutes);

app.listen(5000, () => console.log('Server running at port 5000'));

To make sure the application runs properly, run the application by typing the following command in the terminal:

nodemon index

If it goes well, it will look like the following image:

img

Up here you have successfully created a "backend".

To make sure the backend is running properly, you can use POSTMAN or the REST Client extensions in VS Code to do some testing.

 

#9. Front-End

For the front-end, I will use React JS.

If you are not familiar with React JS, I suggest you to lern the “React JS Tutorial For Beginners” first.

There are many ways to create a React project. However, the easiest way is "create react app".

Open a new terminal and create a new react project by typing the following command in the terminal:

npx create-react-app frontend

And make sure you are in the “fullstack” folder, like the following picture:

img

If the installation is complete, there will be a "frontend" folder in the "fullstack" folder.

So that in the "fullstack" folder there are two folders, namely: "backend" and "frontend" as shown below:

img

The “backend” folder is the application folder that was built previously using node.js express, while the “frontend” is the application folder that was created using React JS.

Next, go to the “frontend” folder by typing the following command in the terminal:

cd frontend

After that, install react-router-dom, axios, and bulma by typing the following command in the terminal:

npm install react-router-dom axios bulma

After the installation is complete, and to make sure everything goes well, type the following command to run the project:

npm start

If it goes well, it will look like the following image:

img

Then, open your browser and visit the following URL:

http://localhost:3000

Then it will appear as follows:

img

 

#10. Components

Create a folder called “components” inside the “frontend/src” folder.

Then, create component files “ProductList.js”, “AddProduct.js”, and “EditProduct.js” in the “frontend/src/components” folder.

Like the following picture:

img

Then open the "ProductList.js" file, then type the following code:

import { useState, useEffect } from 'react'
import axios from "axios";
import { Link } from "react-router-dom";

const ProductList = () => {
    const [products, setProduct] = useState([]);

    useEffect(() => {
        getProducts();
    }, []);

    const getProducts = async () => {
        const response = await axios.get('http://localhost:5000/products');
        setProduct(response.data);
    }

    const deleteProduct = async (id) => {
        await axios.delete(`http://localhost:5000/products/${id}`);
        getProducts();
    }

    return (
        <div>
            <Link to="/add" className="button is-primary mt-2">Add New</Link>
            <table className="table is-striped is-fullwidth">
                <thead>
                    <tr>
                        <th>No</th>
                        <th>Title</th>
                        <th>Price</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    { products.map((product, index) => (
                        <tr key={ product.id }>
                            <td>{ index + 1 }</td>
                            <td>{ product.title }</td>
                            <td>{ product.price }</td>
                            <td>
                                <Link to={`/edit/${product.id}`} className="button is-small is-info">Edit</Link>
                                <button onClick={ () => deleteProduct(product.id) } className="button is-small is-danger">Delete</button>
                            </td>
                        </tr>
                    )) }
                    
                </tbody>
            </table>
        </div>
    )
}

export default ProductList

Next, open the “AddProduct.js” file, then type the following code:

import { useState } from 'react'
import axios from "axios";
import { useHistory } from 'react-router-dom';

const AddProduct = () => {
    const [title, setTitle] = useState('');
    const [price, setPrice] = useState('');
    const history = useHistory();

    const saveProduct = async (e) => {
        e.preventDefault();
        await axios.post('http://localhost:5000/products',{
            title: title,
            price: price
        });
        history.push("/");
    }

    return (
        <div>
            <form onSubmit={ saveProduct }>
                <div className="field">
                    <label className="label">Title</label>
                    <input 
                        className="input" 
                        type="text" 
                        placeholder="Title" 
                        value={ title }
                        onChange={ (e) => setTitle(e.target.value) }
                    />
                </div>

                <div className="field">
                    <label className="label">Price</label>
                    <input 
                        className="input" 
                        type="text" 
                        placeholder="Price" 
                        value={ price }
                        onChange={ (e) => setPrice(e.target.value) }
                    />
                </div>

                <div className="field">
                    <button className="button is-primary">Save</button>
                </div>
            </form>
        </div>
    )
}

export default AddProduct

Next, open the “EditProduct.js” file, then type the following code:

/* eslint-disable react-hooks/exhaustive-deps */
import { useState, useEffect } from 'react'
import axios from "axios";
import { useHistory, useParams } from 'react-router-dom';

const EditProduct = () => {
    const [title, setTitle] = useState('');
    const [price, setPrice] = useState('');
    const history = useHistory();
    const { id } = useParams();

    const updateProduct = async (e) => {
        e.preventDefault();
        await axios.patch(`http://localhost:5000/products/${id}`,{
            title: title,
            price: price
        });
        history.push("/");
    }

    useEffect(() => {
        getProductById();
    }, []);

    const getProductById = async () => {
        const response = await axios.get(`http://localhost:5000/products/${id}`);
        setTitle(response.data.title);
        setPrice(response.data.price);
    }

    return (
        <div>
            <form onSubmit={ updateProduct }>
                <div className="field">
                    <label className="label">Title</label>
                    <input 
                        className="input" 
                        type="text" 
                        placeholder="Title" 
                        value={ title }
                        onChange={ (e) => setTitle(e.target.value) }
                    />
                </div>

                <div className="field">
                    <label className="label">Price</label>
                    <input 
                        className="input" 
                        type="text" 
                        placeholder="Price" 
                        value={ price }
                        onChange={ (e) => setPrice(e.target.value) }
                    />
                </div>

                <div className="field">
                    <button className="button is-primary">Update</button>
                </div>
            </form>
        </div>
    )
}

export default EditProduct

 

#11. App.js

Open the "App.js" file in the "frontend/src" folder, then change it to the following:

import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import ProductList from "./components/ProductList";
import AddProduct from "./components/AddProduct";
import EditProduct from "./components/EditProduct";

function App() {
  return (
    <Router>
    <div className="container">
      <div className="columns">
        <div className="column is-half is-offset-one-quarter">
          <Switch>
            <Route exact path="/">
              <ProductList />
            </Route>
            <Route path="/add">
              <AddProduct />
            </Route>
            <Route path="/edit/:id">
              <EditProduct />
            </Route>
          </Switch>
        </div>
      </div>
    </div>
    </Router>
  );
}

export default App;

 

#12. Testing

Go back to the browser and visit the following URL:

http://localhost:3000

If it goes well, it will look like the following image:

img

Click the "Add New" button, a form like the following will appear:

img

Enter “Title” and “Price”, then click the “SAVE” button.

If the insert is successful, you will see the addition of data to the product list as shown below:

img

To update data, click one of the "Edit" buttons, a form like the following will appear:

img

Change the “Title” or “Price”, then click the “UPDATE” button.

If the update is successful, you will see changes in the data in the product list as shown below:

img

To delete data, click one of the "Delete" buttons.

If the delete is successful, then the data will be lost from the product list.

 

Conclusion:

The discussion this time is how to create a full stack application with a node.js express in backend and a frontend using React JS.

That way, you have an idea of how to create a modern web application that separates the backend and frontend.

So what are you waiting for, Let's Coding!

Download Source Code

Share:



Sponsorship:


Recommended for you


Comments (0)

Leave a Comment