사고쳤어요
[도서 쇼핑몰] Node.js - 주문 API 구현(mysql 비동기 처리) 본문
주문하기
주문하기는 장바구니에 존재하는 아이템 목록들 중 일부를 선택하여 주문하는 기능이다.
코드 작성에 앞서 주문하기는 다음 3가지의 내용을 진행해야 한다.
1. deliveries 테이블에 새로운 배송 데이터(주소, 수령인, 연락처)를 추가
2. orders 테이블에 새로운 주문 데이터(대표 책 1권, 수량, 가격, 주문자, 배송번호)를 추가
3. ordered_books 테이블에 새로운 주문번호에 맞는 책의 정보들을 추가(다른 책 3권을 시켰다면 3개의 행이 추가됨)
const order = (req, res) => {
const { items, delivery, totalCounts, totalPrice, userId, firstBookTitle } =
req.body;
let deliveryId = 0;
let orderId = 0;
// 먼저 deliveries 테이블에 배송 데이터 추가
const deliverySql = `INSERT INTO deliveries (address, receiver, contact)
VALUES (?, ?, ?);`;
const deliveryValues = [
delivery.address,
delivery.receiver,
delivery.contact,
];
conn.query(deliverySql, deliveryValues, (err, results) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).json({
msg: `Error: ${err.code}`,
});
}
deliveryId = results.insertId;
});
// 이어서 orders 테이블에 주문 데이터 추가
const orderSql = `INSERT INTO orders
(book_title, total_counts, total_price, user_id, delivery_id)
VALUES (?, ?, ?, ?, ?);`;
const orderValues = [
firstBookTitle,
totalCounts,
totalPrice,
userId,
deliveryId,
];
conn.query(orderSql, orderValues, (err, results) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).json({
msg: `Error: ${err.code}`,
});
}
orderId = results.insertId;
});
// 이어서 ordered_books 테이블에 주문의 전체 도서 데이터 추가
const orderedBooksSql = `INSERT INTO ordered_books (order_id, book_id, counts)
VALUES ?;`;
let orderedBooksValues = [];
items.forEach((item) => {
orderedBooksValues.push([orderId, item.bookId, item.counts]);
});
conn.query(orderedBooksSql, [orderedBooksValues], (err, results) => {
if (err) {
return res.status(StatusCodes.BAD_REQUEST).json({
msg: `Error: ${err.code}`,
});
}
});
// 모든 과정이 완료되었다면 OK 리턴
return res.status(StatusCodes.OK).end();
};
그러나 위 순서대로 코드를 실행하면
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 에러가 발생한다.
위 코드가 비동기적으로 실행되기 때문에 순서가 보장되지 않고 동시에 실행되기 때문이다.
node.js의 require(mysql2/promise)과 mysql 비동기 처리
const mysql = require("mysql2/promise");
require("dotenv").config();
const connection = async () => {
return await mysql.createConnection({
host: "localhost",
user: "root",
password: process.env.MYSQL_PASSWORD,
database: "bookshop",
dateStrings: true,
});
};
module.exports = connection;
promise와 async/await를 활용하여 순서를 지키는 방법도 좋지만 먼저 node.js의 mysql모듈에는 좋은 기능이 있다.
mysql을 require()문으로 정의할 때 뒤에 /promise를 붙여준다면 Promise를 반환하게 되어 async/await을 사용할 수 있다.
따라서 connection 함수를 async로 비동기 처리한 뒤 return await를 통해 기다리도록 순서를 설정해줄 수 있다.
const connection = require("../mysql");
const order = async (req, res) => {
const conn = await connection();
const { items, delivery, totalCounts, totalPrice, userId, firstBookTitle } =
req.body;
let deliveryId;
let orderId;
// 먼저 deliveries 테이블에 배송 데이터 추가
const deliverySql = `INSERT INTO deliveries (address, receiver, contact)
VALUES (?, ?, ?);`;
const deliveryValues = [
delivery.address,
delivery.receiver,
delivery.contact,
];
const [deliveryResults] = await conn.execute(deliverySql, deliveryValues);
deliveryId = deliveryResults.insertId;
// 이어서 orders 테이블에 주문 데이터 추가
const orderSql = `INSERT INTO orders
(book_title, total_counts, total_price, user_id, delivery_id)
VALUES (?, ?, ?, ?, ?);`;
const orderValues = [
firstBookTitle,
totalCounts,
totalPrice,
userId,
deliveryId,
];
const [orderResults] = await conn.execute(orderSql, orderValues);
orderId = orderResults.insertId;
// items(장바구니 id)로부터 book_id, counts 받아옴
const getCartItemsSql = `SELECT book_id, counts FROM cart_items WHERE id IN (?);`;
const orderItems = await conn.query(getCartItemsSql, orderItems);
// 이어서 ordered_books 테이블에 주문의 전체 도서 데이터 추가
const orderedBooksSql = `INSERT INTO ordered_books (order_id, book_id, counts)
VALUES ?;`;
let orderedBooksValues = [];
orderItems.forEach((item) => {
orderedBooksValues.push([orderId, item.bookId, item.counts]);
});
const [orderedBooksReults] = await conn.query(orderedBooksSql, [
orderedBooksValues,
]);
// 이어서 장바구니의 목록 삭제
const deleteResults = await deleteCartItems(conn, items);
// 모든 과정이 완료되었다면 OK 리턴
return res.status(StatusCodes.OK).json(results);
};
const deleteCartItems = async (conn, items) => {
const sql = `DELETE FROM cart_items WHERE id IN (?);`;
return await conn.query(sql, items);
};
주문 내역 조회
const getOrders = async (req, res) => {
const conn = await connection();
const sql = `SELECT orders.id, book_title, total_counts, total_price, created_at,
address, receiver, contact
FROM orders LEFT JOIN deliveries
ON orders.delivery_id = deliveries.id;`;
const [rows, fields] = await conn.query(sql);
return res.status(StatusCodes.OK).json(rows);
};
주문 상세 조회
const getOrderDetails = async (req, res) => {
const { id } = req.params;
const conn = await connection();
const sql = `SELECT book_id, book_title, author, price, counts,
FROM ordered_books LEFT JOIN books
ON ordered_books.book_id = books.id
WHERE order_id = ?;`;
const [rows, fields] = await conn.query(sql, id);
return res.status(StatusCodes.OK).json(rows);
};
'웹 풀스택' 카테고리의 다른 글
[도서 쇼핑몰] Node.j JWT 적용하기 (0) | 2025.03.24 |
---|---|
[Node.js] Promise와 비동기 처리 (0) | 2025.03.19 |
[도서 쇼핑몰] Node.js - 장바구니 API 구현 (0) | 2025.03.17 |
[도서 쇼핑몰] Node.js - 도서 조회 시 좋아요 개수, 여부 함께 보내주기 (0) | 2025.03.14 |
[도서 쇼핑몰] Node.js - 좋아요 API 구현 (0) | 2025.03.14 |