MySQL에 접속해 Cmarket 데이터베이스를 생성해야 합니다.
미리 구성되어 있는 Cmarket 스키마
를 기반으로 MySQL에 cmarket 데이터베이스의 테이블을 생성합니다.
웹 서버가 MySQL 데이터베이스에 대해 CRUD 중 Create, Read가 가능해야 합니다.
mysql에 접속해서 cmarket 데이터베이스를 생성합니다.
CREATE DATABASE cmarket;
CLI(터미널) 환경에서 레포지토리에 진입하여 커맨드를 입력 - schema 복사
mysql -u root -p < server/schema.sql -Dcmarket
CLI(터미널) 환경에서 레포지토리에 진입하여 커맨드를 입력
mysql -u root -p < server/seed.sql -Dcmarket
PATH/TO/YOUR/schema.sql
은 터미널의 현재 위치에서 schema.sql의 위치까지 경로를 지정해야 한다는 의미입니다.
만약 터미널의 위치가 스프린트 폴더라면, 상대경로만 이용해도 충분하므로 server/schema.sql 을 입력합니다.
잘못된 Sql 작성시 DROP DATABASE IF EXISTS [다시 생성하려는 데이터베이스] CREATE DATABASE [다시 생성하려는 데이터베이스]
으로 해결
BATCH MODE 관련 https://dev.mysql.com/doc/refman/8.0/en/batch-mode.html
(1) npm install 명령어로 서버폴더에 필요한 모듈 설치
package.json에 기록된 npm 모듈 mysql
(2) 비밀번호 '환경변수'로 분리해놓음
server/config/config.js에 mySQL과의 연결을 위한 환경 변수 DATABASE_SPRINT_PASSWORD 를 사용하고 있습니다. npm 모듈 dotenv 로 환경 변수를 사용하는 방법을 확인하세요.
.env.example 파일을 꼭 확인해주세요. YOUR_MYSQL_PASSWORD 부분에 로컬 PC의 MySQL 비밀번호를 입력하세요. 쌍따옴표(\")로 감싸거나, 세미콜론(;)으로 마무리하지 않아도 됩니다.
DATABASE_SPRINT_PASSWORD=YOUR_MYSQL_PASSWORD
비밀번호 입력을 완료했으면, 파일에 작성한 내용을 환경 변수로 인식하도록 파일의 확장자명 또는 파일의 이름을 .env로 변경해 주세요.
(3) 명령어 npm start 로 서버를 실행합니다.
웹 개발에 있어서 라우터는 컨트롤러로 진입할 수 있게 도와주는 endpoint입니다. 따라서 endpoint에 맞게 적절한 라우터를 작성해야 하고, 해당 라우터에 컨트롤러를 연결해야 합니다. 예를 들어 /items URL로 GET 요청을 보낼 경우, items 컨트롤러의 메소드가 실행되도록 만들 수 있습니다.
이때, endpoint에 따라 분리하여 파일 구성을 할 수도 있습니다.
모든 라우터는 server/routes/index.js를 진입점으로 여기고,
여기서 endpoint에 따라 다시 분기됩니다.
따라서 server/routes/index.js 와 server/routes/items.js 파일을 통해 라우팅 방식에 대해서 함께 확인하기 바랍니다.
server/db/index.js 파일에서는 데이터베이스와 서버 인스턴스를 연결하기 위해 mysql 모듈을 사용합니다.
https://www.npmjs.com/package/mysql#establishing-connections
server/models/index.js 파일에는 controller 에서 사용할 orders, items 모델을 정의해야 합니다.
기본적인 구조만 제공되며 server/db/index.js 의 함수를 불러온 뒤, SQL 쿼리문으로 DB의 정보를 처리합니다. 데이터베이스 쿼리는 비동기 요청인 점을 반드시 고려해야 합니다.
🗄 Cmarket Database
🗺 -------- Cmarket Router
🚀 Server is starting on 4000
✓ users router 파일이 존재해야 합니다
✓ orders controller에는 get, post 메소드가 각각 존재해야 합니다
GET /users/1/orders 200 2 - 5.029 ms
✓ GET /users는 orders controller의 get 메소드를 실행합니다
POST /users/1/orders 201 166 - 42.370 ms
✓ POST /users는 orders controller의 post 메소드를 실행합니다 (46ms)
(1) Router는 서버에 요청이 들어왔을때 분기를 해준다.
<app.js>
const express = require('express');
const indexRouter = require('./routes');
const cors = require('cors');
const morgan = require('morgan');
const app = express();
const port = 4000;
app.use(
morgan(' :method :url :status :res[content-length] - :response-time ms')
);
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/', indexRouter);
// Router 요청을 한다.
module.exports = app.listen(port, () => {
console.log(` 🚀 Server is starting on ${port}`);
});
(1-1) items에 관련한 endpoint 요청이 오게 되면 itemsRouter로 갑니다.
<routes - index.js>
const express = require('express');
const router = express.Router();
const itemsRouter = require('./items');
// TODO: Endpoint에 따라 적절한 Router로 연결해야 합니다.
router.use('/items', itemsRouter);
module.exports = router;
(1-2) itemsRouter로 가게되면 controller로 연결은 해준다.
<routes - itmes.js>
const router = require('express').Router();
const controller = require('./../controllers');
// GET /items Router와 Controller를 연결합니다.
router.get('/', controller.items.get);
module.exports = router;
(1-3) 여기로 연결이 된다.
<controllers index.js>
const models = require('../models');
module.exports = {
items: {
get: (req, res) => {
models.items.get((error, result) => {
if (error) {
res.status(500).send('Internal Server Error');
} else {
res.status(200).json(result);
}
});
},
},
orders: {
get: (req, res) => {
const userId = req.params.userId;
models.orders.get(userId, (error, result)=> {
if (error) {
res.status(500).send('Internal Server Error');
} else {
res.status(200).json(result);
}
})
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
post: (req, res) => {
const userId = req.params.userId;
const { orders, totalPrice } = req.body;
if(!orders){
return res.status(400).end();
}else{
models.orders.post(userId, orders, totalPrice, (error,result) => {
if (error) {
console.log(error)
res.status(200).send('Internal Server Error');
} else {
res.status(201).json(result);
}
})
}
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
},
};
(2) 이와 같이 users도 연결을 해줘야 한다.
<routes index.js>
const express = require('express');
const router = express.Router();
const itemsRouter = require('./items');
const usersRouter = require("./users");
// TODO: Endpoint에 따라 적절한 Router로 연결해야 합니다.
router.use('/items', itemsRouter);
router.use('/users', usersRouter);
module.exports = router;
🕹 -------- Cmarket Controller
GET /items 200 617 - 1.548 ms
✓ GET /items 요청에 성공했을 경우 상태코드 200을 보내야합니다.
GET /users/1/orders 200 2 - 1.608 ms
✓ GET /users/:userId/orders 요청에 성공했을 경우 상태코드 200을 보내야합니다.
POST /users/1/orders 400 - - 0.704 ms
✓ POST /users/:userId/orders 요청에서 클라이언트가 잘못된 요청을 했을 경우 상태코드 400을 보내야합니다.
POST /users/1/orders 201 166 - 27.312 ms
✓ POST /users/:userId/orders 요청에 성공했을 경우 상태코드 201을 보내야합니다.
const models = require('../models');
module.exports = {
items: {
get: (req, res) => {
models.items.get((error, result) => {
if (error) {
res.status(500).send('Internal Server Error');
} else {
res.status(200).json(result);
}
});
},
},
orders: {
get: (req, res) => {
const userId = req.params.userId;
models.orders.get(userId, (error, result)=> {
if (error) {
res.status(500).send('Internal Server Error');
} else {
res.status(200).json(result);
}
})
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
post: (req, res) => {
const userId = req.params.userId;
const { orders, totalPrice } = req.body;
if(!orders){
return res.status(400).end();
}else{
models.orders.post(userId, orders, totalPrice, (error,result) => {
if (error) {
console.log(error)
res.status(200).send('Internal Server Error');
} else {
res.status(201).json(result);
}
})
}
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
},
};
✨-------- Cmarket Model
GET /items 200 617 - 0.934 ms
✓ 데이터베이스에 저장된 상품 목록을 가져와야합니다.
POST /users/1/orders 201 166 - 25.909 ms
✓ 주문내역을 데이터베이스에 저장해야합니다.
POST /users/1/orders 201 166 - 43.013 ms
POST /users/1/orders 201 166 - 53.448 ms
GET /users/1/orders 200 622 - 1.261 ms
✓ 데이터베이스에 저장된 주문내역을 가져와야합니다. (104ms)
const db = require('../db');
module.exports = {
items: {
get: (callback) => {
// TODO: Cmarket의 모든 상품을 가져오는 함수를 작성하세요
const queryString = `SELECT * FROM items`;
db.query(queryString, (error, result) => {
callback(error, result);
});
},
},
orders: {
get: (userId, callback) => {
const queryString = `SELECT orders.id, name, image, price, total_price, order_quantity, created_at
FROM orders
LEFT JOIN users
ON users.id = orders.user_id
LEFT JOIN order_items
ON orders.id = order_items.order_id
LEFT JOIN items
ON items.id = order_items.item_id
WHERE users.id = ?`;
const params = [userId];
db.query(queryString, params, (err,result)=>{
callback(err, result);
});
},
post: (userId, orders, totalPrice, callback) => {
const queryString = `INSERT INTO orders (user_id, total_price) VALUES ?`
console.log(queryString);
const params = [[userId, totalPrice]];
db.query(queryString, [params], (err, result) => {
if(result){
const queryString2 = `INSERT INTO order_items (order_id, item_id, order_quantity) VALUES ?`;
const params2 = orders.map(el => {
return [result.insertId, el.itemId, el.quantity];
});
db.query(queryString2, [params2], (err, result)=>{
callback(err, result);
})
}
else{
callback(err, result)
}
});
}
}
}