데브코스

[8주차 - DAY3] 주문 API 구현

미안하다 강림이 좀 늦었다 2024. 4. 17. 13:58

 

 

주문 DB

ERD

 

delivery 테이블 생성

 

orders 테이블 생성

 

orderedBook 테이블 생성

 

 

주문하기 API 구현

orders 테이블의 delivery_id 컬럼이 delivery 테이블을 참고하고 있고, orderedBook 테이블의 order_id 컬럼이 orders 테이블을 참조하고 있으므로 데이터 삽입 순서는 아래와 같다.

  1. delivery 테이블
  2. orders 테이블
  3. orderedBook 테이블

 

설계 수정

Method POST
URI /orders
HTTP Status Code 성공(201)
Request Body {
    items: [
        {
            cartId: 장바구니 도서 id,
            bookId: 도서 id,
            quantity: 수량
        },
        …
    ],
    delivery: {
        address: “주소”,
        receiver: “이름”,
        contact: “010-0000-0000”
    },
    totalPrice: 총 금액,
    totalQuantity: 총 수량,
    userId: 사용자 id,
    firstBookTitle: “대표 도서 제목
}
Response Body  

 

delivery 테이블 insert

results를 출력하면 위와 같은 객체를 볼 수 있다. 'insertId' 항목이 삽입된 데이터의 id를 알려주기 때문에 이 값을 저장해 놓으면 별도의 쿼리문을 실행하지 않아도 된다. 이 insertId는 orders 테이블에 데이터를 삽입할 때 필요하다.

const order = (req, res) => {
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
    let deliveryId;

    let sql = `INSERT INTO delivery (address, receiver, contact) 
                    VALUES (?, ?, ?)`;
    let values = [delivery.address, delivery.receiver, delivery.contact];
    conn.query(sql, values,
        (err, results) => {
            if (err) {
                console.log(err);
                return res.status(StatusCodes.BAD_REQUEST).end();
            }

            deliveryId = results.insertId;
        });
};

 

orders 테이블 insert

쿼리 실행 결과의 insertId는 orderedBook 테이블에 데이터를 삽입할 때 필요하므로 별도로 저장해놔여 한다.

const order = (req, res) => {
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
    let deliveryId;
    let orderId;

    // ...

    sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id) 
                VALUES (?, ?, ?, ?, ?)`
    values = [firstBookTitle, totalQuantity, totalPrice, userId, deliveryId];
    conn.query(sql, values,
        (err, results) => {
            if (err) {
                console.log(err);
                return res.status(StatusCodes.BAD_REQUEST).end();
            }
            orderId = results.insertId;
        });
};

 

orderedBook 테이블 insert

이중 배열을 사용하면 쿼리를 여러 번 실행하지 않아도 복수개의 데이터를 한번에 삽입할 수 있다. 쿼리에 넣을 변수인 2차원 배열을 파라미터로 적어줄 때 대괄호를 입혀서 넣어야 한다.

const order = (req, res) => {
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
    let deliveryId;
    let orderId;

    // ...

    sql = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`;
    values = [];
    items.forEach((item) => {
        values.push([orderId, item.bookId, item.quantity]);
    });
    conn.query(sql, [values],
        (err, results) => {
            if (err) {
                console.log(err);
                return res.status(StatusCodes.BAD_REQUEST).end();
            }
            res.status(StatusCodes.CREATED).json(results);
        })
};

 

 

고쳐야 할 것

console.log(deliveryId)가 insertId를 저장하는 것보다 더 빨리 실행되기 때문에 콘솔에 나타나는 결과가 undefined이다. 

const order = (req, res) => {
    const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } = req.body;
    let deliveryId;

    // ...

    conn.query(sql, values,
        (err, results) => {
            // ...
            
            deliveryId = results.insertId;
        });
    console.log(deliveryId) // undefined
};

 

 

배운 점

  • 방금 INSERT 한 데이터의 id 값을 가져오는 방법에는 두 가지 방법이 있다.
    • 쿼리 실행 결과 객체의 insertId 값 가져오기
    • LAST_INSERT_ID() 함수를 사용하거나 MAX(id)를 조회한다. LAST_INSERT_ID() 함수는 시간차 때문에 오류가 발생할 수 있으므로 사용을 지양한다.
  • 이중 배열을 사용하면 복수개의 데이터를 한 번에 삽입할 수 있다.
  • 코딩 컨벤션이란 코딩 스타일 규칙을 말한다. 구성원들이 읽고 관리하기 쉽게 해 준다.