sprint-cmarket-database 개발과정
🛒 시작하기
이번에는 데이터베이스를 통해, 데이터를 주고받는 것을 배운다.
- 주의: 이번 스프린트는
npm test
하면 자동으로 서버가 실행되고 테스트가 진행된다. 그래서 켜둔 서버를 끄고 테스트를 돌려야한다.
-
mysql에 접속하여 cmarket 데이터베이스를 생성한다.
-
미리 구성되어 있는 Cmarket 스키마를 기반으로 MySQL에 cmarket 데이터베이스의 테이블을 생성한다.
$ mysql -u root -p < server/schema.sql -Dcmarket
명령어를 이용하여 cmarket 데이터베이스에 테이블을 생성.$ mysql -u root -p < server/seed.sql -Dcmarket
명령어를 이용하여 생성한 테이블에 기반이 되는 데이터를 저장.
명령어에 명시된 파일을 들어가보면 schema.sql
에는 스키마가 미리 작성되어 있다.
seed.sql
에는 데이터를 추가하는 명령어가 작성되어 있다.
-> 미리 파일을 만들어두고 명령어를 실행하는 방식으로 데이터베이스에 테이블을 생성하고 데이터를 추가할 수 있는 것 같다.
스프린트를 진행하면서 잘못된 sql로 작성해서 이상한 데이터들이 쌓여있었다.
DROP DATABASE cmarket;
를 통해 데이터베이스를 전부 삭제하고,
위 1번부터 2번까지 과정을 다시 반복하였다.
🛒 파일 파악하기 (server 폴더)
-
package.json
을 확인하면dependencies
에mysql
이 있다.
이 모듈은 서버와 데이터베이스서버를 연결해주는 역할을 하는 것 같다. -
config/config.js
파일은.env
와 연결되어 있다. 보통.env
파일을 통해 비밀번호를 설정하고,config.js
파일에서 기본값을 고정 시켜주는 것 같다. -
app.js
파일에는 express로 서버를 만드는 코드가 이미 작성되어있다.
(express.js는 node.js환경에서 웹어플리케이션 혹은 API를 제작하기 위해 사용되는 인기있는 프레임워크) -
controllers/index.js
get, post 요청을 처리하는 코드가 이미 작성되어 있다. API문서를 참고하여 controller가 어떻게 서버에 요청을 보내고 응답을 전송하는지 알 수 있다. -
db/index.js
파일에서는 mysql 모듈을 사용해 데이터베이스와 서버를 연결한다. -
models/index.js
파일은 controller에서 사용할 orders, items 모델을 정의해야 한다. 기본적인 틀은 짜여져 있고,db/index.js
의 함수를 불러와 SQL을 사용하여 쿼리문을 통해 DB의 정보를 처리한다. 데이터베이스 쿼리는 반드시 비동기 요청인점을 고려해야 한다.
🛒 진행하기
테스트 항목은 3가지 였다.
- 해당 유저가 작성한 모든 주문을 가져오는 함수를 작성
- 해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성
- Cmarket의 모든 상품을 가져오는 함수를 작성
Cmarket의 모든 상품을 가져오는 함수를 작성
마지막 항목을 제일 먼저 구현하기로 했다. 데이터베이스를 확인했을 때, 모든 상품이 있는 테이블에만 데이터가 존재했기 때문이다.
items: {
get: (callback) => {
// TODO: Cmarket의 모든 상품을 가져오는 함수를 작성하세요
callback(err, result);
}
}
- 유어클래스에 있는 예제를 이용하여 작성했다.
var sql = "INSERT INTO customers (name, address) VALUES ?";
var params = [
["John", "Highway 71"],
["Peter", "Lowstreet 4"],
["Amy", "Apple st 652"],
["Hannah", "Mountain 21"],
["Michael", "Valley 345"],
["Sandy", "Ocean blvd 2"],
["Betty", "Green Grass 1"],
["Richard", "Sky st 331"],
["Susan", "One way 98"],
["Vicky", "Yellow Garden 2"],
["Ben", "Park Lane 38"],
];
con.query(sql, [params], function (err, result) {
if (err) throw err;
console.log("Number of records inserted: " + result.affectedRows);
});
- sql 에 쿼리문을 작성하고, 아래 con.query를 이용하면 되는 것 같았다.
그대로 가져와서 모든 상품을 가져오는 쿼리문을 작성하고 테스트를 돌렸다.
con이 정의되지 않았다는 에러가 떴다.
파일의 맨위에const db = require('../db');
이 코드가 작성되어 있었다.해당 파일에 들어가보니 con 이라는 변수가 작성되어 있었고module.exports = con;
를 통해 내보내고 있었다.
-
db.query ~~로 작성하고 기존에 작성되어 있던
callback(err, result);
코드를if (err) throw err;
대신 넣어주었다. -
클라이언트를 실행하여 확인하니 모든 상품이 잘 보였다!
해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성
그 다음 두번째 항목을 먼저 구현하기로 했다.
첫번째 항목은 유저의 주문목록을 가져오는 것인데, 이것은 데이터베이스에서 가져와야 하기 때문이다. 그래서 데이터베이스에 주문 요청을 저장하는 항목이 먼저 구현되어야 한다고 생각했다.
orders: {
get: (userId, callback) => {
// TODO: 해당 유저가 작성한 모든 주문을 가져오는 함수를 작성하세요
callback(err, result);
},
post: (userId, orders, totalPrice, callback) => {
// TODO: 해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성하세요
callback(err, result);
}
}
- 파라미터 파악
post: (userId, orders, totalPrice, callback)
를 보면,
유저아이디, 주문들, 총금액을 받아온다. 데이터베이스에 각각 추가해줘야 하는 내용이다.
그리고 테스트 케이스를 확인해보니 아래처럼 작성되어 있었다.
즉, orders.itemId, orders.quantity 를 통해 쿼리를 날려야 한다.
orders: [ { itemId: 1, quantity: 2 },
{ itemId: 2, quantity: 5 }]
- 쿼리 두번 날리기
데이터베이스를 확인해보면 아래처럼 구성되어 있다.
먼저 orders 테이블에 userId, totalPrice를 추가해줘야 하고, orders의 id(PK)를 받아온다.
order_items 테이블에 orders.itemId와 orders.quantity를 추가해줘야 한다. 더불어 orders 테이블의 id(PK)를 order_items의 order_id(FK)에 넣어줘야한다.
그래야 연결이 되기 때문이다.
let sql = `INSERT INTO ~~~`;
// 1번째 쿼리문
db.query(sql, (err, result) => {
if (result) { // result 받아와서 있으면 다음 쿼리문 실행
let sql = `INSERT INTO ~~ VALUES ?;`; // ? 를 사용하면
let params= []; // param 문이 자동으로 들어간다.
// 2번째 쿼리문
db.query(sql, [params], (err, result) => { // [params] 를 넣어줘야한다.
callback(err, result);
})
}
})
- PK 받아오기
INSERT INTO 가 받아오는 객체를 확인하면 PK를 받아오는 방법을 알 수 있다.
result.insertId
를 이용하면 된다.
if (result) {console.log(result)}
를 찍어보면 아래 내용을 확인할 수 있다.
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 1,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0
}
- 데이터베이스에 잘 저장하는지 확인해보자
위 화면처럼 아이템을 담아서 구매하기 버튼을 누른다.
잘 추가되어있다!
해당 유저가 작성한 모든 주문을 가져오는 함수를 작성
- 테스트케이스를 보고 어떤 데이터를 가져와야 하는지 확인한다.
expect(data[0].id).to.equal(1);
expect(data[0].image).to.equal('../images/egg.png');
expect(data[0].name).to.equal('노른자 분리기');
expect(data[0].order_quantity).to.equal(2);
expect(data[0].price).to.equal(9900);
expect(data[0].total_price).to.equal(79800);
expect(data[3].id).to.equal(2);
expect(data[3].image).to.equal('../images/fish.jpg');
expect(data[3].name).to.equal('잉어 슈즈');
expect(data[3].order_quantity).to.equal(2);
expect(data[3].price).to.equal(3900);
expect(data[3].total_price).to.equal(10700);
이 6가지의 데이터를 가져오면 테스트는 통과하지만,
클라이언트를 확인해보면 주문내역 탭을 눌렀을 때, 에러가 뜬다.
추가로 orders.created_at
데이터까지 가져오면 아래처럼 잘 작동한다.
🛒 후기
드디어 3티어 아키텍처를 경험해봤다.
부분적으로 작성하면 가능하지만, 밑바닥부터 만들기 시작하면 내가 해낼 수 있을까?
그래도 다 만들고 난 후에는 너무 뿌듯했다.
test 스크립트는 시간제한이 2000 이었지만, 자꾸 타임아웃 에러가 떠서 시간을 더 늘려야했다. 나중에는 쿼리문을 엄청 작성해놓고 타임아웃이 뜨자 파일에 대해 의심했는데, 스프린트를 다 완성한 지금 와서는 내가 쿼리를 개판으로 날렸기 때문에 일어난 일이었다 ^^;
어렵지만 너무 재미있다. 나중에는 나 혼자서 클라이언트, 서버, 데이터베이스까지 만들어보고싶다! 우선은 여태 배운거 다 복습하기!
스프린트 진행했던 파일들 차곡차곡 잘 모아두면 나중에 좋은 참고서가 될 것이라고 생각한다.
Author And Source
이 문제에 관하여(sprint-cmarket-database 개발과정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@flobeeee/sprint-cmarket-database-개발과정저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)