Create a project with "backend" folder
npm init -y
npm i express mysql2 cors dotenv
npm i -D nodemon
add "start":"nodemon server.js"
Folder Structure (5) & File (2)
config
controllers
middlewares
models
routes
======================
.env
server.js
server.js
require('dotenv').config()
const express = require('express');
const cors = require('cors');
const app = express();
app.get('/', (req, res) => {
res.send('<h1>Hello, Express.js Server!</h1>');
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
Run server (npm start) & Test
npm start
END OF PART 1: Initial Local Backend Setup
config/db.js
require('dotenv').config()
const mysql = require('mysql2/promise');
//CONNECT TO DATABASE
const pool = mysql.createPool({
host: process.env.HOST,
user: process.env.USER,
database: process.env.DATABASE,
password: process.env.PASSWORD,
});
module.exports = pool
.env
PORT=3000
HOST=localhost
USER=root
PASSWORD=
DATABASE=db1
READ
routes/userRoute.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController')
router.get('/', (req, res) => {
res.send('Welcome to PKE')
})
router.get('/users', userController.getAllUsers )
module.exports = router;
controllers/userController.js
const userModel = require('../models/userModel')
const getAllUsers = async(req, res) => {
try {
const [data] = await userModel.getAllUsers()
res.status(200).json({
message: 'GetAllUsers success',
data: data
})
} catch (error) {
res.status(500).json({
message: 'Server Error',
serverMessage: error
})
}
}
module.exports = {
getAllUsers,
}
models/userModel.js
const pool = require('../config/db')
const getAllUsers = () => {
const SQLQuery = "SELECT * FROM users"
return pool.execute(SQLQuery)
}
module.exports = {
getAllUsers,
}
server.js
require('dotenv').config()
const express = require('express');
const cors = require('cors');
const app = express();
// INCLUDE ROUTE FILES
const userRoute = require('./routes/userRoute');
// USE
app.use(cors());
app.use(express.json());
app.use('/pke', userRoute);
app.get('/', (req, res) => {
res.send('<h1>Hello, Express.js Server!</h1>');
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
Test READ
http://localhost:3000/pke/users
CREATE
routes/userRoute.js
ADD THIS CODE
router.post('/users', userController.createNewUser)
controllers/userController.js
ADD THIS CODE
const createNewUser = async(req, res) => {
try {
const body = req.body
const [data] = await userModel.createNewUser(body)
res.status(200).json({
message: 'Create New User success',
data: body
})
} catch (error) {
res.status(500).json({
message: 'Server Error',
serverMessage: error
})
}
}
module.exports = {
getAllUsers,
createNewUser,
}
models/userModel.js
ADD THIS CODE
const createNewUser = (body) => {
const {name, email, password, age} = body
const SQLQuery = "INSERT INTO users (name, email, password, age) VALUES (?, ?, ?, ?)"
return pool.execute(SQLQuery,[name, email, password, age])
}
module.exports = {
getAllUsers,
createNewUser,
}
Test CREATE
(ThunderClient / Postman)
UPDATE
routes/userRoute.js
ADD THIS CODE
router.patch('/user', userController.updateUser)
controllers/userController.js
ADD THIS CODE
const updateUser = async(req, res) => {
try {
const body = req.body
const [data] = await userModel.updateUser(body)
res.status(200).json({
message: 'Update User success',
data: body
})
} catch (error) {
res.status(500).json({
message: 'Server Error',
serverMessage: error
})
}
}
module.exports = {
getAllUsers, createNewUser,
updateUser
}
models/userModel.js
ADD THIS CODE
const updateUser = (body, ID) => {
const { id, name, email, password, age } = body
const SQLQuery = "UPDATE users SET name=?, password=?, age=? WHERE id=?"
return pool.execute(SQLQuery,[name, password, age, id])
}
module.exports = {
getAllUsers, createNewUser,
updateUser,
}
Test UPDATE
(ThunderClient / Postman)
DELETE
routes/userRoute.js
ADD THIS CODE
router.delete('/user/:id', userController.deleteUser)
controllers/userController.js
ADD THIS CODE
const deleteUser = async(req, res) => {
try {
const params = req.params
const [data] = await userModel.deleteUser(params)
res.status(200).json({
message: 'DELETE User success',
data: data
})
} catch (error) {
res.status(500).json({
message: 'Server Error',
serverMessage: error
})
}
}
module.exports = {
getAllUsers, createNewUser, updateUser,
deleteUser,
}
models/userModel.js
ADD THIS CODE
const deleteUser = (params) => {
const id = params.id
const SQLQuery = "DELETE FROM users WHERE id=?"
return pool.execute(SQLQuery,[id])
}
module.exports = {
getAllUsers, createNewUser, updateUser,
deleteUser,
}
Test DELETE
(ThunderClient / Postman)
READ By ID
routes/userRoute.js
ADD THIS CODE
router.get('/user/:id', userController.getUserById)
controllers/userController.js
ADD THIS CODE
const getUserById = async(req, res) => {
try {
const params = req.params
const [data] = await userModel.getUserById(params)
res.status(200).json({
message: 'GET User By ID success',
data: data
})
} catch (error) {
res.status(500).json({
message: 'Server Error',
serverMessage: error
})
}
}
module.exports = {
getAllUsers, createNewUser, updateUser,
deleteUser, getUserById,
}
models/userModel.js
ADD THIS CODE
const getUserById = (params) => {
const id = params.id
const SQLQuery = "SELECT * FROM users WHERE id=?"
return pool.execute(SQLQuery,[id])
}
module.exports = {
getAllUsers, createNewUser, updateUser,
deleteUser, getUserById,
}
Test
Open the project folder using Terminal
npm create vue@latest
Project name: "frontend"
Answer Yes only to (i) Vue Router and (ii) Pinia
Open the project folder using VSCode and follow the instructions
END OF PART 1: Local Setup (FRONTEND)
npm i axios
App.vue
Delete content EXCEPT -->
Delete/Empty all content of
assets
components
main.js
Delete -->
views/HomeView.vue
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
</template>
END OF PART 2: Local Hello World / Welcome (FRONTEND)
READ ( frontend --> backend )
frontend/src/views/HomeView.vue
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
<table class="table">
<thead>
<tr>
<th>Bil</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in display" :key="item.id">
<td> {{ idx+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
</tr>
</tbody>
</table>
<!-- <pre> {{ display }}</pre> -->
</template>
<script setup>
import { onMounted, ref } from 'vue';
import axios from 'axios';
import router from '@/router';
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
let display = ref('')
onMounted(()=>getAll())
async function getAll(){
try {
const {data} = await axios.get( store.axiosURL + '/users');
display.value = data.data;
} catch (error) {
console.error(error);
}
}
</script>
frontend/src/stores/Counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const axiosURL = 'http://localhost:3000/pke'
return { axiosURL, }
})
Test
backend (npm start)
frontend (npm run dev)
CREATE ( frontend --> backend )
frontend/src/views/HomeView.vue
ADD THIS CODE
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
<button @click="addNew"> add New User </button>
<hr>
<table class="table">
<thead>
<tr>
<th>Bil</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in display" :key="item.id">
<td> {{ idx+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
</tr>
</tbody>
</table>
<!-- <pre> {{ display }}</pre> -->
</template>
<script setup>
import { onMounted, ref } from 'vue';
import axios from 'axios';
import router from '@/router';
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
let display = ref('')
onMounted(()=>getAll())
async function getAll(){
try {
const {data} = await axios.get( store.axiosURL + '/users');
display.value = data.data;
} catch (error) {
console.error(error);
}
}
const addNew=()=>{router.push('/add')}
</script>
frontend/src/views/AddView.vue
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
<table class="table">
<thead>
<tr>
<th>Bil</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in display" :key="item.id">
<td> {{ idx+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
</tr>
</tbody>
</table>
<!-- <pre> {{ display }}</pre> -->
</template>
<script setup>
import { onMounted, ref } from 'vue';
import axios from 'axios';
import router from '@/router';
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
let display = ref('')
onMounted(()=>getAll())
async function getAll(){
try {
const {data} = await axios.get( store.axiosURL + '/users');
display.value = data.data;
} catch (error) {
console.error(error);
}
}
</script>
frontend/src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AddView from '../views/AddView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/add',
name: 'add',
component: AddView
}
]
})
export default router
Test
DELETE ( frontend --> backend )
frontend/src/views/HomeView.vue
ADD THIS CODE
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
<button @click="addNew"> add New User </button>
<hr>
<table class="table">
<thead>
<tr>
<th>Bil</th>
<th>Name</th>
<th>Age</th>
<th>Action 1</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in display" :key="item.id">
<td> {{ idx+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td @click="goDelete(item)">delete</td>
</tr>
</tbody>
</table>
<!-- <pre> {{ display }}</pre> -->
</template>
<script setup>
import { onMounted, ref } from 'vue';
import axios from 'axios';
import router from '@/router';
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
let display = ref('')
onMounted(()=>getAll())
async function getAll(){
try {
const {data} = await axios.get( store.axiosURL + '/users');
display.value = data.data;
} catch (error) {
console.error(error);
}
}
const addNew=()=>{router.push('/add')}
const goDelete=(item)=>{
store.itemDelete = item
router.push('/delete')
}
</script>
frontend/src/views/DeleteView.vue
<template>
<div>
<h2>This is a delete user page</h2>
<button @click="onBack">Back</button>
<button @click="onDelete">Delete</button>
<hr>
<pre> {{ store.itemDelete }}</pre>
</div>
</template>
<script setup>
import router from "../router/index.js";
import axios from "axios";
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
const onBack = () => { router.push('/') }
const onDelete = async () => {
try {
const { id } = store.itemDelete
const response = await axios.delete(store.axiosURL + '/user/' + id);
console.log(response.data)
router.push('/')
} catch (error){
console.error(error);
}
}
</script>
frontend/src/router/index.js
ADD THIS CODE
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AddView from '../views/AddView.vue';
import DeleteView from '../views/DeleteView.vue';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/add',
name: 'add',
component: AddView
},
{
path: '/delete',
name: 'delete',
component: DeleteView
}
]
})
export default router
frontend/src/stores/Counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const axiosURL = 'http://localhost:3000/pke'
const itemDelete = reactive({})
return { axiosURL, itemDelete }
})
Test
UPDATE ( frontend --> backend )
frontend/src/views/HomeView.vue
ADD THIS CODE
<template>
<h1>Welcome to Vue3 (June 2024)</h1>
<button @click="addNew"> add New User </button>
<hr>
<table class="table">
<thead>
<tr>
<th>Bil</th>
<th>Name</th>
<th>Age</th>
<th>Action 1</th>
<th>Action 2</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, idx) in display" :key="item.id">
<td> {{ idx+1 }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td @click="goDelete(item)">delete</td>
<td @click="goUpdate(item)">update</td>
</tr>
</tbody>
</table>
<!-- <pre> {{ display }}</pre> -->
</template>
<script setup>
import { onMounted, ref } from 'vue';
import axios from 'axios';
import router from '@/router';
import { useCounterStore } from '../stores/counter';
const store = useCounterStore();
let display = ref('')
onMounted(()=>getAll())
async function getAll(){
try {
const {data} = await axios.get( store.axiosURL + '/users');
display.value = data.data;
} catch (error) {
console.error(error);
}
}
const addNew=()=>{router.push('/add')}
const goDelete=(item)=>{
store.itemDelete = item
router.push('/delete')
}
function goUpdate(item){
store.itemUpdate = item
router.push('/update')
}
</script>
frontend/src/router/index.js
ADD THIS CODE
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AddView from '../views/AddView.vue';
import DeleteView from '../views/DeleteView.vue';
import UpdateView from '../views/UpdateView.vue';
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/add',
name: 'add',
component: AddView
},
{
path: '/delete',
name: 'delete',
component: DeleteView
},
{
path: '/update',
name: 'update',
component: UpdateView
}
]
})
export default router
frontend/src/views/UpdateView.vue
<template>
<div>
<h2>This is an update user page</h2>
<button @click="onBack">Back</button>
<hr>
<form>
<div>
<br>
<label>Email</label><br>
<input type="text" v-model="store.itemUpdate.email" disabled>
</div><br>
<div>
<label>Name</label><br>
<input type="text" v-model="store.itemUpdate.name">
</div><br>
<div>
<label>Password</label><br>
<input type="text" v-model="store.itemUpdate.password">
</div><br>
<div>
<label>Age</label><br>
<input type="text" v-model="store.itemUpdate.age">
</div><br>
</form>
<button type="submit" @click="onSubmit">Submit</button><br><br>
<!-- <pre>{{ store.itemUpdate }} </pre> -->
</div>
</template>
<script setup>
import router from "../router/index.js";
import axios from 'axios';
import { useCounterStore } from '../stores/counter.js';
const store = useCounterStore();
const onBack=()=>{router.push('/')}
async function onSubmit(){
try {
const response = await axios.patch( store.axiosURL + '/user', store.itemUpdate );
router.push('/')
// console.log(data.data);
//display.value = data.data;
} catch (error) {
console.error(error);
}
}
</script>
frontend/src/stores/Counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const axiosURL = 'http://localhost:3000/pke'
const itemDelete = reactive({})
const itemUpdate = reactive({})
return { axiosURL, itemDelete, itemUpdate }
})
Test
GET User By ID ( frontend --> backend )
frontend/src/views/HomeView.vue
ADD THIS CODE
<h1>Welcome to Vue3 (June 2024)</h1>
<button @click="addNew"> add New User </button>
<button @click="getById"> Get User By ID </button>
<hr>
...
...
function getById(){
router.push('/getById')
}
frontend/src/router/index.js
ADD THIS CODE
import GetByIdView from '../views/GetByIdView.vue';
...
...
{
path: '/getById',
name: 'getById',
component: GetByIdView
},
frontend/src/views/GetByIdView.vue
<template>
<div>
<h2>This is a Get By ID user page</h2>
<button @click="onBack">Back</button>
<hr>
<form>
<div>
<br>
<label>User ID</label><br>
<input type="text" v-model="user.id">
</div><br>
</form>
<button type="submit" @click="onSubmit">Submit</button><br><br>
<!-- <pre>{{ user }} </pre> -->
<pre>{{ result }} </pre>
</div>
</template>
<script setup>
import { reactive } from 'vue';
import router from "../router/index.js";
import axios from 'axios';
import { useCounterStore } from '../stores/counter.js';
const store = useCounterStore();
const user = reactive({})
const result = reactive({})
const onBack = () => { router.push('/') }
async function onSubmit() {
try {
const response = await axios.get(store.axiosURL + '/user/' + user.id);
result.value = response.data;
console.log(response)
} catch (err) {
console.error(err);
}
}
</script>
Test
1. Create database
3. Create Sub-Domain
4. Setup Nodejs
5. Check Point
6. Prepare Backend zip file
Use file explorer to zip all files EXCEPT node_modules
Example: server.zip
Delete the default "server.js"
Upload the server.zip
Extract the server.zip
Delete the server.zip
STOP APP
Run NPM Install
START APP
7. Check Point
Use ThunderClient to check other CRUD
END OF PART 1: cPanel Backend Setup
1. Update & Save axiosURL in counter.js
e.g: https://mvc.mlrguitm.com/pke
npm run build
Using file explorer, zip the file
Example: dist.zip
Upload the dist.zip
Extract the dist.zip
Delete the dist.zip
Move content of dist folder to one level up.
Success !