JEST
로 만든 Test Case 를 수정하고, 통과하기어제 만든 chatterbox-database 는 일단 GET, POST 요청은 잘 받아지고, sequel 등에서 DB query 를 발송해봐도 잘 적용된다. 그러나, JEST 로 만든 Test Case로부터 발송되는 요청과 DB query 는 일부가 적용되지 않아 통과하지 못 하고 있다. 그래서 그 문제를 오늘 마저 해결해 보기 위해 고군분투 중이다!
Test case 의 request 모듈을 통한 POST
request 는 서버에서 잘 받아주고 있다. 200번대 status code 가 나오고, 그리고 내가 설정한 대로 "POST request를 보내면, request body 에 담아 보낸 JSON 을 담아 response 하라" 라는 대로 test case 에서 body 에 잡아준 JSON 도 잘 나온다. 그리고 그게 DB query 로 넘어가는 것도 맞는데,
확인해 본 결과, 정황상 메시지는 잘 가는데, truncate
을 통해 매 test 가 시작하기 전 messages
table 을 초기화 하기에 안 보이는 것을 확인하였다. 즉 쿼리는 잘 받아주고, 잘 전송하고 있다.
result
scope 문제확인해 봤는데, test case 는 callback 을 걸어주지 않고 바로 넘겨서 result 에 접근할 수 없던 것 같다. 일단 추측은 그러하다. 그래서 일단은 수정 전 test case 를 통해 다시 실험해보았다.
이번에는 도저히 이해가 되지 않아 reference code 를 참조하였다. Schema Design 은 나와 거의 똑같았다. 그런데, 서버에서 들어오는 응답을 처리해주는 부분과, 그리고 그 응답과 같이 SQL을 연동하는 부분이 달랐다. 공부는 이렇게 하려고 한다. 문제를 풀다가 답지를 보는 느낌이라 뭔가 어제오늘 이틀동안 고군분투한 스스로에게 참 아쉽지만, 이해가 안 되는 부분이 있으면 정답을 보고 이해를 한 다음 내 것으로 만들면 된다는 마음가짐으로 용기있게(?) 참조하게 되었다.
다음과 같은 과정으로 공부해 볼 예정이다.
CREATE TABLE messages (
id INT NOT NULL AUTO_INCREMENT,
roomname varchar(255),
text text(1024),
userid varchar(255) NOT NULL,
createdAt datetime DEFAULT CURRENT_TIMESTAMP,
updatedAt datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
/* Create other tables and define schemas for them here! */
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
username varchar(255),
createdAt datetime DEFAULT CURRENT_TIMESTAMP,
updatedAt datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
messages
라는 table 은 수동으로 입력해서 넣어주어야 하는 column으로 roomname
, text
, userid
가 존재한다. 그리고 DEFAULT
값을 통해 자동으로 할당해주는 createdAt
과 updatedAt
이라는 column 이 있다. 마지막으로 AUTO-INCREMENT
속성이 있는 id
를 PRIMARY KEY
로 사용한다.
users
라는 table 은 수동으로 입력해서 넣어주어야 하는 column으로 id
, username
이 존재한다. 그리고 DEFAULT
값을 통해 자동으로 할당해주는 createdAt
과 updatedAt
이라는 column 이 있다. 마지막으로 AUTO-INCREMENT
속성이 있는 id
를 PRIMARY KEY
로 사용한다.
//db model
module.exports = {
messages: {
get: function(callback) {
// fetch all messages
// text, username, roomname, id
var queryStr = "select messages.id, messages.text, messages.roomname, users.username
from messages left outer join users on (messages.userid = users.id)
order by messages.id desc";
db.query(queryStr, function(err, results) {
callback(err, results);
});
},
post: function(params, callback) {
// create a message for a user id based on the given username
var queryStr = `insert into messages(text, userid, roomname)
value (?, (select id from users where username = ? limit 1), ?)`;
db.query(queryStr, params, function(err, results) {
callback(err, results);
});
}
},
users: {
get: function(callback) {
// fetch all users
var queryStr = "select * from users";
db.query(queryStr, function(err, results) {
callback(err, results);
});
},
post: function(params, callback) {
// create a user
var queryStr = "insert into users(username) values (?)";
db.query(queryStr, params, function(err, results) {
callback(err, results);
});
}
}
};
//server model
var models = require("../models");
module.exports = {
messages: {
get: function(req, res) {
models.messages.get(function(err, results) {
if (err) {
/* do something */
res.send(err);
}
res.json(results);
});
},
post: function(req, res) {
var params = [req.body.text, req.body.username, req.body.roomname];
models.messages.post(params, function(err) {
if (err) {
/* do something */
res.send(err);
}
res.sendStatus(201);
});
}
},
users: {
get: function(req, res) {
models.users.get(function(err, results) {
if (err) {
/* do something */
}
res.json(results);
});
},
post: function(req, res) {
var params = [req.body.username];
models.users.post(params, function(err) {
if (err) {
/* do something */
}
res.sendStatus(201);
});
}
}
};
첫번째 경우 : /classes/messages
로 GET
request 가 들어왔을 때
messages.id
, messages.text
, messages.roomname
, users.username
을 SELECT
한다.messages
table 을 기준으로 users
table 과 LEFT JOIN
을 한다.messages.userId
와 users.username
이 같은 항목들을 추린다. queryString
을 통해 db.query
메서드로 쿼리를 발송한다.callback(err, results)
로 messages.get
메서드의 인자로 받는 callback function 의 보내준다.models
라는 이름으로 exports
하여 [messages.post](http://messages.post)
메서드에서 활용한다.models.messages.get
의 callback argument 로 express
의 request, response 함수를 넘겨준다if (err)
), res.send(err)
를 통해 에러를 담아 response 를 한다.body-parser
의 .json(arg)
를 통해, results
를 JSON 형태로 바꾸어 response 를 한다.두번째 경우 : /classes/messages
로 POST
request 가 들어왔을 때
res.body
를 통해 POST
로 날아온 body 를 받는다.
그것을 params
라는 변수를 선언하고, 그 안에 req.body
의 각 항목을 배열 형태로 저장한다
POST
request 를 발송한다고 가정한다.params = [req.body.roomname, req.body.text, req.body.userId]
를 통해 배열 형태로 저장한다.그리고 models.messages.get
의 인자로 params
와 query handler(가제)함수를 넘겨준다
res.send(err)
를 통해 에러를 담아 response 를 한다.POST
request 가 이상없이 잘 받아들여졌다고 201 상태코드를 담아 response 를 한다 (res.sendStatus(201)
)위의 과정을 거쳐 만들어진 params
와 query handler
함수를, exports
를 통해 내보내서 인자로 받게 된 messages.get
함수를 활용한다.
message.id
, messages.text
, messages.roomname
, users.username
을 보내주기 위해 SELECT
로 먼저 선택한다JOIN
을 활용한다.INNER JOIN
이 아닌 OUTER JOIN
을 활용하자 (여기서는 LEFT
를 사용했다)user.id
와 messages.userId
항목이 같은 경우를 JOIN
의 조건으로 제한한다.SELECT messages.id, messages.text, messages.roomname, user.name
FROM messages
LEFT JOIN user ON messages.userId = users.id
해당 쿼리문을 queryStr
로, POST
응답을 통해 인자로 넘겨받은 params
를 queryArg
로, 그리고 (err, results)
를 핸들링하는 함수에서는 callback 인자로 넘겨받은 query handler 에다가 에러가 발생하는 경우 3-1 시나리오처럼 res.send(err)
를 통해 에러를 담아 response 를 한다.
만약 에러가 존재하지 않는다면, 3-2 시나리오처럼 이상없이 잘 받아들여졌다고 201 상태코드를 담아 response 를 한다 (res.sendStatus(201)
)
세번째 경우 : /classes/users
로 GET
request 가 들어왔을 때
messages.id
, messages.text
, messages.roomname
, users.username
을 SELECT
한다.messages
table 을 기준으로 users
table 과 LEFT JOIN
을 한다.messages.userId
와 users.username
이 같은 항목들을 추린다. queryString
을 통해 db.query
메서드로 쿼리를 발송한다.callback(err, results)
로 messages.get
메서드의 인자로 받는 callback function 의 보내준다.models
라는 이름으로 exports
하여 [messages.post](http://messages.post)
메서드에서 활용한다.models.messages.get
의 callback argument 로 express
의 request, response 함수를 넘겨준다if (err)
), res.send(err)
를 통해 에러를 담아 response 를 한다.body-parser
의 .json(arg)
를 통해, results
를 JSON 형태로 바꾸어 response 를 한다.일단 시간이 늦어서 여기까지만 하려고 한다. 내일은 상기한 과정들을 전부 끝내, 완성한 코드를 pull request 할 생각이다. 그리고 오늘 여기에서 만난 형과 express 로 구현한 socket 통신을 통해 캐치마인드처럼 서로가 서로의 그림을 볼 수 있는 웹페이지의 서버를 같이 검수(?) 했는데, 그 덕분에 socket 통신과 P5.js
라는 그림을 그리는 라이브러리를 알게 되었다. 여담으로 통신을 하는 경우, 실시간 통신 측면에서는 socket 통신이 좋지만 요즘은 거의 다 HTTP 방식의 통신을 이용한다는 썰도 들었다.
또 이걸 하면서 든 생각은 "토이프로젝트로 캐치마인드를 하나 만들어보는건 어떨까?" 였다. React 로 프론트를 구성하고, express 로 백엔드를 구성하고. DB는 채팅창을 옆에 만들어서 그 채팅들을 저장하는 식으로 하고. 상상만 해도 뭔가 재밌다!
뭐, 여튼. 그렇다. 오늘의 공부는 일단 여기서 마무리...
개형은 대략 이런 모습?