Today What I Learned
Javascript를 배우고 있습니다. 매일 배운 것을 이해한만큼 정리해봅니다.
1. Express 개념 정리
-
Express란?
- Express는 Node.js 환경에서 동작하는 웹 애플리케이션 프레임워크으로 미들웨어를 붙여서 사용할 수 있는 것과 라우팅 기능을 제공하는 장점이 있다.
- node.js 기반이며 npm을 통해 다운 받을 수 있다.
- 기존에 bare node.js에서는 http.createserver 기능을 통해 서버를 생성하였으나, express 프레임워크에서는 express의 instance를 만들어 서버를 사용한다.
- Express에서 에러 처리는 매개변수가 4개(err, req, res, next)인 미들웨어 함수를 사용하고, 이를 이용해 에러 발생 시 console.err(err.stack) 형식을 취한다.
-
Middleware란?
- 미들웨어는 요청 객체(req), 응답 객체(res) 사이에서 중간 처리 역할을 수행한다.
- 미들웨어를 통해 요청에 대한 응답 처리 전까지 다양한 일을 처리할 수 있다.
- 실제로 body parser나 cors 처리 등은 http를 이용한 서버 구축에서 꽤 긴 문장을 차지했는데, 이러한 미들웨어를 사용하면서 코드가 굉장히 깔끔하고 짧게 작성되었고 payload를 파싱해서 보여주거나 cors 요청에 손쉽게 응답할 수 있었다.
[출처: express 홈페이지]
-
Routing?
- 클라이언트로부터 받은 요청에 어떻게 응답할 것인지를 결정하는 행위
- Route handler는 요청을 처리하는 콜백함수이다.
- 각 라우트는 1개 혹은 1개 이상의 라우트 핸들러 함수를 가지고 있어서 해당하는 method가 인지되었을 때 실행된다.
[출처: https://poiemaweb.com/express-basics]
- 운영하는 웹 서비스의 규모가 크고 다양한 api가 사용될 때 routing을 통해 유용하게 분기점을 구분할 수 있다.
2. express로 서버 리팩토링 하기
- node.js와 서버에 대해서 배우는 과정에서 서버는 분기를 잘 해준다는 점이 매우 매력적이었다. 물론 클라이언트에서도 다양한 함수를 통해 이벤트 발생 시 핸들링을 해주지만 서버단에서의 라우팅이나 요청 대응은 뭔가 더 체계적이고 안정감 있게 지원을 해주는 느낌이었다고 해야 하나? 아무튼... Express로 리팩토링 하기
- 중점적으로 익힌 내용
- 미들웨어, 라우팅이 적용된 서버 리팩토링 : http를 이용한 서버를 구축하면서 서버 구축의 기본적인 개념과 요소를 배웠다면 이번에는 이들을 편리하고 빠르게 대체해줄 수 있는 프레임워크를 통해 리팩토링 해보는 것이 목표였다.
- 고전했던 부분
- 라우팅 적용: 몇일 전 내가 구축했던 chatter-box 클라이언트는 단일 패스로 구성되어서 서버로 요청을 하더라도 분기점이 딱히 필요하지 않았다. 상황이 이렇다 보니 라우팅의 필요성을 크게 느끼지 못했고, express 서버 내 method로 대응하는 것과 express.Router를 이용한 분기 처리 후 method에 따른 대응 코드를 작성해주는 것을 크게 구분하지 못했다. 개념을 확실히 하기 위해서 페어들에게도 질문하고, 엔지니어와의 시간에 직접 질문을 했다. 한 개의 웹서비스 내 다양한 패스를 통해 로그인/로그아웃/조회 등 다양한 api를 주고 받아야 할 수 있다는 예시를 듣고 나서 라우팅의 필요성과 정확한 개념을 이해하게 되었다. 앞으로는 개념 학습을 하면서 실제 서비스 구현의 예제도 함께 찾아봐야겠다.
3. Code Review
- 전 날 작성했던 chatter box server는 크게 basic-server.js(server creation이 담김), request-handler.js(서버에 요청이 도달했을 때 핸들러 함수를 담음 - 이 파일이 메인이었음), 그리고 data.js(db storage creation 대신 사용했던 데이터 파일)로 구성되어 있었다.
- express 프레임워크를 사용하면서 basic-server.js에서는 기존의 server creation과 에러 대응과 routing을 구현했다. request-handler 대신 route.js를 만들어서 서버에 도달해 path 기준으로 라우팅 된 get, post 요청에 대응하는 함수를 구현했다. 그리고 똑같이 data.js를 db 성격으로 사용하였다.
- Express부터 배웠다면 http.createserver 방식은 별로 쳐다보고 싶지 않았을 것 같다. 특히 body parsing 같은 경우는 express 4.16버전 이후부터는 내장 모듈로 제공된다고 하는데, chunk를 모아 buffer에서 다시 객체로 파싱해주는 작업이 얼마나 자주 일어나는지 직접 손으로 쳐보고 나서 더 깊이 공감할 수 있어서 좋았다.
좋은 배움이었으나 앞으로는 시간 효율을 위해서라도 그냥 express만 쓰고 싶다...ㅎㅎㅎ
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const route = require("./route");
const PORT = 3001;
const ip = "127.0.0.1";
app.use(cors());
app.use(bodyParser.json());
app.use("/classes/messages", route);
app
.use((req, res) => {
res.status(404).send("no such a matching address");
})
.use((err, req, res) => {
console.err(err.stack);
res.statsu(500).send("internal server error");
});
app.listen(PORT, () => {
console.log(`server listen on ${ip} : ${PORT}`);
})
const { storage } = require("./data.js");
let { idNum, date } = require("./data.js");
const express = require("express");
const router = express.Router();
router.use((req, res, next) => {
console.log(`http method is ${req.method}, url is ${req.url}`);
next();
});
router
.route("/")
.get((req, res) => {
res.status(200).send(storage);
})
.post((req, res) => {
if (req.body.text === "" || req.body.username === "") {
console.log(req.body.username, req.body.text);
res.status(400).send();
} else {
date = new Date();
console.log("post", req.body);
req.body["date"] = date;
req.body["id"] = idNum;
storage.results.push(req.body);
res.status(201).end(JSON.stringify({ id: idNum }));
idNum++;
}
});
module.exports = router;
const storage = { results: [] };
let idNum = 0;
let date = "";
module.exports = { storage, idNum, date };