질문 제목이 장황한점 죄송합니다. mvc에 해당하는 model, view, control을 순서대로 코드로 사용해봤습니다.
model:
const Product = require("../models/products");
async function FindOne(id, next) {
try {
const product = await Product.findOne({
where: { id },
});
if (product === null) {
throw new Error("null");
}
return product;
} catch (err) {
if (err.message === "null") {
return new Error("no Product");
} else {
return new Error(err.message);
}
}
}
async function FindAll() {
try {
const product = await Product.findAll({});
if (product === null) {
throw new Error("null");
}
return product;
} catch (err) {
if (err.message === "null") {
return new Error("no Product");
} else {
return new Error(err.message);
}
}
}
async function getBefore(id) {
try {
const BeforeProducts = await Product.findOne({
where: { id },
});
const resultByOldProducts = JSON.stringify(BeforeProducts.dataValues);
return resultByOldProducts;
} catch (err) {
if (
err.message ===
"Cannot read properties of null (reading 'dataValues')"
) {
return new Error("no Product");
} else {
return new Error(err.message);
}
}
}
async function getAfter(id) {
try {
const AfterProducts = await Product.findOne({
where: { id },
});
const resultByNewProducts = JSON.stringify(AfterProducts);
return resultByNewProducts;
} catch (err) {
if (
err.message ===
"Cannot read properties of null (reading 'dataValues')"
) {
return new Error("no Product");
} else {
return new Error(err.message);
}
}
}
async function Create(package) {
try {
const { id, name, price, origin, type } = package;
const createdProduct = await Product.create({
id,
name,
price,
origin,
type,
});
return createdProduct;
} catch (err) {
if (err.message === "Validation error") {
return new Error("same Product");
} else if (err.message || "notNull Violoation") {
return new Error("Form Null");
} else {
return new Error(err.message);
}
}
}
async function Update(package, paramsId) {
try {
const { id, name, price, origin, type } = package;
await Product.update(
{
id,
name,
price,
origin,
type,
},
{
where: { id: paramsId },
}
);
return 0;
} catch (err) {
if (err.message === "Validation error") {
return new Error("same Product");
} else if (err.message || "notNull Violoation") {
return new Error("Form Null");
} else {
return new Error(err.message);
}
}
}
async function Destroy(paramsId) {
try {
await Product.destroy({
where: { id: paramsId },
});
return 0;
} catch (err) {
return new Error(err.message);
}
}
module.exports = {
FindOne,
FindAll,
getBefore,
getAfter,
Create,
Update,
Destroy,
};
view:
const express = require("express");
const controllWorker = require("../controller/productController");
const router = express.Router();
router
.route("/")
.get(controllWorker.getProductMain)
.post(controllWorker.createProduct);
router
.route("/:id")
.get(controllWorker.getProductDetail)
.patch(controllWorker.modifyProduct)
.delete(controllWorker.removeProduct);
module.exports = router;
control:
const dataWorker = require("../data/productData");
async function getProductDetail(req, res, next) {
const paramsId = req.params.id;
const product = await dataWorker.FindOne(paramsId, next);
if (product.message) {
return next(product);
}
res.locals.id = paramsId;
res.locals.productName = product.name;
res.locals.productPrice = product.price;
res.locals.productOrigin = product.origin;
res.locals.productType = product.type;
res.render("productInfo");
}
async function getProductMain(req, res, next) {
const products = await dataWorker.FindAll();
if (products.message) {
return next(products);
}
const result = products.map((value, index) => {
const productNames = [];
productNames.push(products[index].name);
console.log(products[index].dataValues);
return productNames;
});
result.shift();
res.locals.productNames = result;
res.render("productMain");
}
async function createProduct(req, res, next) {
const package = req.body;
const products = await dataWorker.Create(package);
if (products.message) {
return next(products);
}
const result = JSON.stringify(products);
const message = "The product has been created";
res.status(201).render("productCreate", { message, result });
}
async function modifyProduct(req, res, next) {
const paramsId = req.params.id;
const package = req.body;
const getOld = await dataWorker.getBefore(paramsId);
if (getOld.message) {
return next(getOld);
}
const updater = await dataWorker.Update(package, paramsId);
if (updater.message) {
return next(updater);
}
const getNew = await dataWorker.getAfter(paramsId);
if (getNew.message) {
return next(getNew);
}
const message = "The product's info has been modified";
res.status(200).render("productUpdateDelete", {
message,
getOld,
getNew,
});
}
async function removeProduct(req, res, next) {
const paramsId = req.params.id;
const getOld = await dataWorker.getBefore(paramsId);
if (getOld.message) {
return next(getOld);
}
const destroyer = await dataWorker.Destroy(paramsId);
if (destroyer.message) {
return next(destroyer);
}
const getNew = await dataWorker.getAfter(paramsId);
if (getNew.message) {
return next(getNew);
}
const message = "The product's info has been removed ";
res.status(203).render("productUpdateDelete", {
message,
getOld,
getNew,
});
}
module.exports = {
getProductDetail,
getProductMain,
createProduct,
modifyProduct,
removeProduct,
};
에러처리 미들웨어를 아래와 같이 사용하고 있습니다.
app.use((err, req, res, next) => {
console.log(" ### Error Detected! ###");
if (err.message === "no Product") {
res.locals.warning = "No applicable products found";
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.locals.error.status = 404;
res.locals.message =
"The requested product could not be found, please go back.";
console.error(err);
return res.render("occasionalError");
}
if (err.message === "same Product") {
res.locals.warning = "A product with the same name exists";
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.locals.error.status = 400;
res.locals.message =
"The name of the product cannot be the same, so please reset the name";
console.error(err);
return res.render("occasionalError");
}
if (err.message === "Form Null") {
res.locals.warning = "One of the forms is not filled in";
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.locals.error.status = 400;
res.locals.message =
"You forgot to fill out the form. Please check your input";
return res.render("occasionalError");
}
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.locals.error.status = 500;
console.error(err);
res.render("error");
});
model쪽 코드에서 시퀄라이즈를 이용해서 sql 데이터베이스에 접근하여 데이터를 crud 할 수 있게 되어있습니다. 프로미스를 쉽게 처리하기 위해 async await 문법을 사용했고 오류가 난다면 catch로 로직이흐르게 되어 에러를 new Error()을 사용해서 정의합니다.
문제는 control쪽 코드를 보시면 model과 유사하게 async await 을 사용하여 model쪽에서 리턴한 프로미스 객체를 처리할 수 있게 할 수 있게 해줍니다. 그 대신 await 뒤에는 항상 에러를 리턴받은 것을 대비해서 조건문으로 에러 처리를 하게 해줘야 합니다.
이렇게 조건문이 도배된 이유는 model쪽 코드에서 catch 에서 에러를 한번에 app.js에 존재하는 에러처리 미들웨어로 보내주지 못해서 (model에서 next()를 사용해봤는데 control로 리턴된거 같은 효과가 납니다.) control의 코드는 view에서 모듈로 사용되는 함수들이기 때문에 라우터에서 next(에러 매개변수)를 사용해서 app.js에 있는 에러처리 미들웨어로 한번에 이동이 가능하게 됩니다. 그 대신 매번 조건문을 사용해야 하기 때문에 코드 가독성이 보기 좋지 않습니다. 따라서 control에서 하는 에러처리를 없애고 model의 catch를 통해서 한번에 에러를 app.js에 있는 에러처리 미들웨어로 이동시키는 방법을 알고 싶습니다. 계속해서 프론트앤드 유저분들에게 백앤드 질문을 해서 죄송하지만 만약 이 해결을 아시는분이 계신다면 알려주시면 감사하겠습니다.