티스토리 뷰
이번 과제는 client 가아닌 server위주로 볼것이다.
모델과 컨트롤러 관계성, 모델이 데이터베이스와 어떤식으로 연결되는지 유의하면서 공부해야한다.
Cmarket Database
1. 지금까지 배웠던. SQL 문법. query를 NODE.JS app에서 쿼리하는것을 공부할거다.
이전에 배웠던 im-sprint-statesairline-server의 경우 in-memory 방식으로 데이터를 저장했던것.
데이터를 내 컴퓨터에서 in-memory 방식으로 저장했던것이다.
2. 클라이언트의 HTTP 요청에 따라 CRUD API를 구현할 수 있다. (CRUD: Create, Read, Update, Delete)
이제부터 배울것들을 보면, get 요청일때, post 요청일때 등등(HTTP방식) express프레임워크를 사용하여,
HTTP요청이 들어오면 그에 따른 작업(라우트 작업)을 하여
2-1 SQL CRUD 구현(모델 <- 데이터관련)
2-2 HTTP응답을 날리는 작업을 구현해줄것이다.(컨트롤러)
이번과제에서 해야할 것은 이것이다.
- 사용자가 웹사이트에 접속한다. (Uses)
- Controller는 사용자가 요청한 웹페이지를 서비스 하기 위해서 모델을 호출한다. (Manipulates)
- 모델은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후에 그 결과를 리턴한다.
- Controller는 Model이 리턴한 결과를 View에 반영한다. (Updates)
- 데이터가 반영된 VIew는 사용자에게 보여진다. (Sees)
초기작업
npm install을 통하여 필요한 설치를 해준다.
우리는 이전에는 in-memory를 많이사용했으나. 지금 해야할것은 새로운 tier! 즉 . sql 데이터베이스를 사용할것이다.
CREATE DATABASES cmarket; , CREATE DATABASES cmarket_test 을 해주고 유어클래스에서 했던 필요한 작업들을 한 후에
use cmarket; <= 사용한다.
.env 환경변수 파일만들어주기
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);
module.exports = app.listen(port, () => {
console.log(` 🚀 Server is starting on ${port}`);
});
express모듈을 가져온다, 이후 app= express() 사용.
cors를 (사용)허용하고있다.
app.js는 서버를 여는 중심 역할을 하고있다. = app.listen부분(앱 객체가 가지고있는 메소드 중에 listen을 통하여 서버연결!)
가장 큰 뼈대같은 역할.
app.use로 app이 사용하고있는 모든것들을 살펴보자.
1.
morgan? <- 배우지 않았지만 HTTP요청에대한 log를 남겨주는 미들웨어라고한다.
morgan을 사용한것은 서버에 연결되었을때 HTTP요청에 따라서 console.log처럼 찍힌다.
2. cors()도 허용해준다.
3.정보가 이동될때는 json화 되어서 움직인다. json() <- client에서 fetch후에 제이슨화 시켜된것을 보내고 읽으려면 다시 json()화 시켜서 원래대로 돌려놔야한다. 그렇기에 전범위에서 app.use(express.json()) 을 사용한다.
4. 라우츠 파일을 필요로하고, 전범위에서 사용하고있다. routes가 어떻게 사용되고있나. 분기가 어떻게 되는지 이제 routes 로 이동해서 알아봐야한다.
const indexRouter = require('./routes');
app.use('/', indexRouter);
ROUTES 폴더 분석
routes 폴더에 현재있는값 : index.js, items.js
아래는 아무것도 작성이 안된 값들
//index.js
const express = require('express');
const router = express.Router();
const itemsRouter = require('./items');
// Endpoint에 따라 적절한 Router로 연결해야 한다.
router.use('/items', itemsRouter);
module.exports = router;
1. 설치한 express 사용시 express 사용한다고 가져오고
2. 위의 express.Router()사용법처럼, 라우팅을 위해서 router라는 변수에 담아서 사용한다.
3. itemsRouter는 아이템즈파일에서 라우팅하려고 가져오고있는것.
4. router.use('/items',itemRouter) <= Router 연결방법이다. : ~/items 가 적히면 itemsRouter 가 실행,즉 라우터 연결됨.
//items.js
const router = require('express').Router();
const controller = require('./../controllers');
// GET /items Router와 Controller를 연결합니다.
router.get('/', controller.items.get);
module.exports = router;
item.js 를 보자.
1. router사용을 위해서 index.js에서 햇던것처럼 router 변수에 사용할수있게 담아준다. 필요해서 가져오고, 라우터 함수사용하고.
2. controller와 연결해준다. (컨트롤러에 있는 객체 안에 객체 item, get 의 값을 사용.)
이것을 토대로 아래서 필요한것을 구현해보자.
구현해야할 정보를 파악한다.
users router파일이 존재해야한다고하니 만들어준다.
users.js파일을 만든다.
1. user.js도 위와비슷한 비슷한 형태로 만들어야 할것같은 감이온다. + post가 필요하다고한다.
//index.js에 추가해주기
const express = require('express');
const router = express.Router();
const itemsRouter = require('./items'); // 이것처럼 user.js 라우터를 가져온다.
const usersRouter = require('./users');
// Endpoint에 따라 적절한 Router로 연결해야 한다.
router.use('/items', itemsRouter);
router.use('/users',usersRouter);
module.exports = router;
-------------------------
//새로만든파일 users.js
const router = require('express').Router();
const controller = require('./../controllers');
// GET,POST /users Router와 Controller를 연결합니다.
router.get('/:userId/orders', controller.orders.get); //컨트롤러 API를 통해 써야할정보 확인가능
router.get('/:userId/orders', controller.orders.post);
module.exports = router;
💡users.js에서 보면 결국
/users/:userId/orders에 대한 get요청을 받으면 controller.orders.get을 호출할 것이고,
/users/:userId/orders에 대한 post요청을 받으면 controller.orders.post을 호출할 것이다.
그럼 controller에 가서 어떤 함수가 호출되는지를 살펴보자.
이렇게천천히 라우터 구현은 끝이다.
다음작업 컨트롤러로 가보자.
Controllers : 이벤트 처리담당 폴더 분석
시작전. MVC 컨트롤러의 기능을 다시 생각해보자. => 조작하는 코드! (모델,뷰의 다리역할,이벤트처리담당)
💡Model에게 클라이언트로 부터 요청 받은것을 모델에게 넘겨줘서 그것을 바탕으로 모델이 필요한 정보를 가져오게된다.
가져온정보 응답으로 클라이언트에게 전달. (아! REST API 요청 응답을 줘야겠구나. req, res)
//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;
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
post: (req, res) => {
const userId = req.params.userId;
const { orders, totalPrice } = req.body;
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
},
},
};
처음배우는단계에서 어떻게 구현할지모르는것은 당연하다.
나와있는 예시를 통해서 구현법을 고민해보자.
/users/:userId/orders에 대한 get요청을 받으면 controller.orders.get을 호출할 것이다.
controller.ordrs.get 부분은 무엇인가? 정답 : 함수.
함수를 실행해주고있다.
요청받은것을 컨트롤러는 => 모델 전달하여 응답을 다시 돌려줘야한다. => models.items.get ! Models에게 전달!
REST API에서 req,res는 클라이언트가 날리는 요청에 응답을 해줘야하니 필요한것은 알겠으나
error result? 이것들은 왜 쓰이는걸까.
이 예시를 이해하기 위해서 models 부분을 살펴봐야한다.
MODELS : 데이터를 주고받는것을 담당! 폴더 분석
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) => {
// TODO: 해당 유저가 작성한 모든 주문을 가져오는 함수를 작성하세요
callback(/* err, result */);
},
post: (userId, orders, totalPrice, callback) => {
// TODO: 해당 유저의 주문 요청을 데이터베이스에 생성하는 함수를 작성하세요
callback(/* err, result */);
}
},
};
callback자리에 컨트롤러에서 구현해야할 코드가 작성되어야한다.
callback === (error, result) => {
callback함수의 인자로 (error,result)를 받았기에, error, result가 들어가야하는구나.
Q :컨트롤러가하고싶은일? 해야하는일?
암온더 넥스트 레벨~~ 넥스트 레벨로 가보시죠!!
NEXT> db폴더는 무엇이고. db.query는 무엇일까?
💡💡 express에서 사용하였던 res.query, res.params와는 다른 query다. 헷갈려서는 안된다.
db의 index.js 분석 : Node.js와 MySQL 연동해주는 폴더임
const mysql = require('mysql');
const dotenv = require('dotenv');
const config = require('../config/config');
dotenv.config();
const con = mysql.createConnection(
config[process.env.NODE_ENV || 'development']
);
con.connect((err) => {
if (err) throw err;
});
module.exports = con;
mysql 부분이다. 맨~위로 올라가면
Q. 공부의 목적이 뭐였는가?
A. 지금까지 배웠던. SQL 문법. query를 NODE.JS app에서 쿼리하는것을 공부할거다.
음? 코드스테이츠에서 가르켜준게없는데..?
공식문서를 공부해야한다. => https://www.w3schools.com/nodejs/nodejs_mysql.asp
Node.js MySQL
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.
www.w3schools.com
참고문서 : https://poiemaweb.com/nodejs-mysql
MySQL 연동 | PoiemaWeb
Node.js(express)와 MySQL 연동
poiemaweb.com
연동프로세스
밑에는 API에서 쓰는방식을 따온거다. 이렇게쓰는건 문법같은거임. 국룰. 그냥 만든사람이 이렇게만듬. 이걸보고 공부함됨
const mysql = require('mysql');
const connection = mysql.createConnection({
host : 'localhost',
user : '< MySQL username >',
password : '< MySQL password >',
database : 'my_db'
});
connection.connect();
connection.query('SELECT * from Users', (error, rows, fields) => {
if (error) throw error;
console.log('User info is: ', rows);
});
connection.end();
1. const.mysql = require('mysql') mysql을 가져와 사용할것이다.
2. node.js와 mysql을 연결해주는방법
const connection = mysql.createconnection~ 블라블라
createconnection은 mysql API를 참고해보면 메소드이다. mysql에서 사용가능한 메소드 (addeventlistner처럼 그냥 메소드)
메소드의 인자로 전달되는 객체에 자신의 데이터베이스 정보(유저명과 패스워드 등)를 입력하여야 한다. <= 말이어려운가? 아래처럼 그냥 객체안에 정보를 넣으라는 얘기다.
const connection = mysql.createConnection({
host : 'localhost',
user : '< MySQL username >',
password : '< MySQL password >',
database : 'my_db'
});
3. connection.connect() 연결을해줌. 우리의 db index.js파일을 분석해보면 connection.query()~ 이윗부분이랑 동일하다.
다른점은 config()라는 파일을 따로만들어줘서 그곳에 데이터베이스 정 유저명,패스워드를 담았기에 그걸 사용한것.
Q.모델에서 해야할것?
A. connection.query부분을 공부한 후 그부분을 모델에 채워줘야한다. (모델파트에 미리쓰여졌던것과 구조가 유사하죠?)
SQL을 Node.js 앱에서 쿼리
con.query를 보아하니(sql, function(err,result){
})
인자로. sql이 들어가야하며 err,result부분 함수가 들어가야한다.
결국 error,result 이부분도 model에게 전달해주기위해서 컨트롤러에서 코드를 작성해준것. 컨트롤러는 그냥 모델에게 정보 전달코드를 작성해주면 되는것이다. 이제 문제로 돌아가서 천천히 풀어보는 일만 남았다. 화이팅

정보를 바탕으로 다시 백백백~ 컨트롤러로 돌아와서 코드를 구현해보자.
✔️npm run test로 컨트롤러 부분 구현해야할 정보확인
자세히보면, GET /items 이부분을 읽어보면 : 요구하는바 = 요청에 성공했을 경우 상태코드 200을 보내야한다.
1. 에러도 사용해야한다. <= 실패시 ? 인터넷 문제구나;.
2. result도 사용해야한다. <= 성공시 : 상태코드 200과 result를 보내주면되겠구나. (json으로 보낸다.)
Post 부분 : 클라이언트 잘못된요청도 있네? 500이 아닌 니잘못 400 ! 포스트는 정보를 가져오는게아닌 업데이트? 시켜주는것이므로 result를 다시 보낼필요는없는것.
테스트에서 요구하는것+ 예시를 참고하여 아래부분을 전부 구현해보자.
//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)
}
})
},
post: (req, res) => {
const userId = req.params.userId;
const { orders, totalPrice } = req.body;
// TODO: 요청에 따른 적절한 응답을 돌려주는 컨트롤러를 작성하세요.
if (!orders || !totalPrice) { //사용자가 잘못된 요청을 보냈을 경우
return res.status(400).send("Error 400");
}
models.orders.post(userId, orders, totalPrice, (error, result) => {
if (error) {
res.status(500).send("Internal Server Error");
} else {
res.status(201).json("success post!");
}
});
},
},
};
POST : 클라이언트가 잘못된 요청을했을경우 <- 하나의 조건문이 더 필요하다. 모델에게 전달안해두되고 바로 응답을보내줌. 사용자잘못. 모델은 데이터조작하는일만하는데 데이터조작,관리할 필요가없어짐. 사용자잘못일경우 컨트롤러선에서 끊어주는것.
여기서 잠시!
const userId = req.params.userId;
// GET http://myserver.com/123/orders
// REQ
// - URL http://myserver.com/123/orders
// - PARAMS
// - {
// userId : 123
// }
다음. MODEL부분은 어려워서 다음장에서...To be continued
'백엔드&컴퓨터사이언스' 카테고리의 다른 글
[데이터베이스] Sequalize : part1 데이터베이스 준비하기 (0) | 2021.12.23 |
---|---|
[데이터베이스][MVC] 과제 flow 완전분석 : im-sprint-cmarket-datagbase2 (0) | 2021.12.22 |
[데이터베이스] MVC (0) | 2021.12.21 |
[데이터베이스] SQL 문법 2. Group by / JOIN (0) | 2021.12.20 |
[데이터베이스] im-sprint-learn-sql (0) | 2021.12.19 |