- Khởi tạo dự án: npm init -y
- Cài đặt Express: npm i express
- Cài đặt Vite Plugin Node: npm i -D vite-plugin-node
- Thêm script start: vite trong package.json
{
...
"scripts": {
"start": "vite"
},
...
}
- Create file server.js
import express from "express";
import router from "./routes";
import connectMongoDB from "./config/dbconfig";
const app = express();
app.use(
express.urlencoded({
extended: true,
})
);
app.use(express.json());
connectMongoDB("mongodb://127.0.0.1:27017/db_nodejs");
app.use("/", router);
export const viteNodeApp = app;
Create file routes/index.js
import { Router } from "express";
import booksRouter from "./books";
import authRouter from "./auth";
const router = Router();
router.get("/", (req, res) => {
res.send("Home");
});
router.use("/books", booksRouter);
router.use("/auth", authRouter);
export default router;
Create file routes/books.js
import { Router } from "express";
import BooksController from "../controllers/books";
import { checkPermisson } from "../middlewares/checkPermisson";
const booksRouter = Router();
const booksController = new BooksController();
booksRouter.get("/", booksController.getAllBooks);
booksRouter.get("/:id", booksController.getBookDetail);
booksRouter.post("/", checkPermisson, booksController.createBook);
booksRouter.put("/:id", checkPermisson, booksController.updateBook);
booksRouter.delete("/:id", checkPermisson, booksController.deleteBook);
export default booksRouter;
Connect MongoDB
- npm i mongoose
- Create file: config/dbconfig.js
- import connectMongoDB vào server.js
import mongoose from "mongoose";
export default async function connectMongoDB(dbUrl) {
try {
//mongodb://127.0.0.1:27017/db_name
await mongoose.connect(dbUrl);
console.log("Connect successfully!!!");
} catch (error) {
console.log("Connect failure!!!");
}
}
Create file models/BookModel.js
Ref: https://mongoosejs.com/docs/schematypes.html
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const BookSchema = new Schema(
{
title: { type: String, required: true },
description: { type: String },
author: { type: String },
image: { type: String },
price: { type: Number },
rate: { type: Number },
},
{ timestamps: true, versionKey: false }
);
const Book = mongoose.model("Book", BookSchema);
export default Book;
Create file controllers/books.js
Ref: https://mongoosejs.com/docs/queries.html
import Book from "../models/BookModel";
import { createValidator } from "../validations/book";
class BooksController {
// GET /books
async getAllBooks(req, res) {
try {
const books = await Book.find();
res.status(200).json({
message: "Get All Books Done",
data: books,
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
// GET /books/:id
async getBookDetail(req, res) {
try {
const book = await Book.findById(req.params.id);
if (!book) {
return res.status(404).json({
message: " Book Not Found",
});
}
res.status(200).json({
message: "Get Book Detail Done",
data: book,
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
// POST /books
async createBook(req, res) {
try {
// validate
const { error } = createValidator.validate(req.body, {
abortEarly: false,
});
if (error) {
const errors = error.details.map((err) => err.message);
return res.status(400).json({
message: errors,
});
}
const book = await Book.create(req.body);
res.status(200).json({
message: "Create Book Done",
data: book,
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
// PUT /books/:id
async updateBook(req, res) {
try {
// validate
const { error } = createValidator.validate(req.body, {
abortEarly: false,
});
if (error) {
const errors = error.details.map((err) => err.message);
return res.status(400).json({
message: errors,
});
}
const book = await Book.findByIdAndUpdate(req.params.id, req.body, {
new: true,
});
res.status(200).json({
message: "Update Book Done",
data: book,
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
// DELETE /books/:id
async deleteBook(req, res) {
try {
const book = await Book.findByIdAndDelete(req.params.id);
if (!book) {
return res.status(404).json({
message: "Book Not Found",
});
}
res.status(200).json({
message: "Delete Book Done",
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
}
export default BooksController;
Authentication and Validation JOI
Create models/UserModel.js
// username, password, email, role: default: "member"
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const UserSchema = new Schema(
{
username: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
},
{ timestamps: true, versionKey: false }
);
const User = mongoose.model("User", UserSchema);
export default User;
Create routes/auth.js
import { Router } from "express";
import AuthController from "../controllers/auth";
const authRouter = Router();
const authController = new AuthController();
authRouter.post("/register", authController.register);
authRouter.post("/login", authController.login);
export default authRouter;
Update routes/index.js
import { Router } from "express";
import booksRouter from "./books";
import authRouter from "./auth";
const router = Router();
router.get("/", (req, res) => {
res.send("Home");
});
router.use("/auth", authRouter);
router.use("/books", booksRouter);
export default router;
Create validations/auth.js
import Joi from "joi";
const registerValidator = Joi.object({
username: Joi.string(),
email: Joi.string().required().email(),
password: Joi.string().required(),
});
const loginValidator = Joi.object({
email: Joi.string().required().email(),
password: Joi.string().required(),
});
export { registerValidator, loginValidator };
Create controllers/auth.js
import User from "../models/UserModel";
import bcryptjs from "bcryptjs";
import { registerValidator, loginValidator } from "../validations/auth";
import jwt from "jsonwebtoken";
import dotenv from "dotenv";
dotenv.config();
class AuthController {
// POST auth/register
async register(req, res) {
try {
// validate
const { error } = registerValidator.validate(req.body, {
abortEarly: false,
});
if (error) {
const errors = error.details.map((err) => err.message);
return res.status(400).json({
message: errors,
});
}
const { username, email, password } = req.body;
// check email co trong db chua findOne
const emailExisted = await User.findOne({
email,
});
if (emailExisted) {
return res.status(400).json({
message: "Email dc dung roi nhe !!!",
});
}
// ma hoa password
const hashPassword = await bcryptjs.hash(password, 10);
const user = await User.create({
username,
email,
password: hashPassword,
});
res.status(201).json({
message: "register done",
data: { ...user.toObject(), password: undefined },
});
} catch (error) {
res.status(400).json({
message: error.message,
});
}
}
// POST auth/login
async login(req, res) {
// validate
const { error } = loginValidator.validate(req.body, {
abortEarly: false,
});
if (error) {
const errors = error.details.map((err) => err.message);
return res.status(400).json({
message: errors,
});
}
// check email
const { email, password } = req.body;
const user = await User.findOne({
email,
});
if (!user) {
return res.status(401).json({
message: "Tai khoan ko ton tai",
});
}
// check password
const checkPassword = await bcryptjs.compare(password, user.password);
if (!checkPassword) {
return res.status(401).json({
message: "Tai khoan ko ton tai",
});
}
// token
const token = jwt.sign({ id: user._id }, process.env.SECRECT_KEY, {
expiresIn: "1d",
});
// res token
res
.status(200)
.json({
message: "login done",
data: { ...user.toObject(), password: undefined },
token,
});
}
}
export default AuthController;
Create middlewares/authenticate.js
import jwt from "jsonwebtoken";
import User from "../models/UserModel";
const checkPermission = async (req, res, next) => {
try {
const token = req.headers.authorization?.split(" ")[1];
if (!token) {
return res.status(401).json({
message: "No Authorization",
});
}
// verify token
const data = jwt.verify(token, process.env.SECRECT_KEY);
if (!data) {
return res.status(401).json({
message: "No Authorization",
});
}
// check user
const user = await User.findById(data.id);
if (!user) {
return res.status(404).json({
message: "Not Found",
});
}
// user.role !== 'admin'
// if(user.role !== 'admin'){
// return res.status(403).json({
// message:'Ban ko co quyen lam viec nay'
// })
// }
next();
} catch (error) {
res.status(400).json({
message: error.message,
});
}
};
export { checkPermission };