Node.js Express와 Middleware

MERN stack은 JavaScript 생태계에서 인기 있는 프레임워크인 MongoDB, Express, React, Node를 지칭하는 말이다. 이 중에서 Express.js는 Node.js 환경에서 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크이다.

npm i express --save 로 설치한다.
--save 옵션은 종속 항목 목록(dependencies)에 추가해주는 역할을 한다.

Express로 구현한 서버는 http 모듈로 작성한 서버보다 미들웨어 추가가 편리하고, 자체 라우터를 제공한다는 장점이 있다. 실제로 직접 코드를 http 모듈을 사용한 것에서 express를 사용하는 방법으로 변경해보았더니 훨씬 코드도 간결해지고 좋았다.

우선 이전에 http 모듈을 사용해 작성했던 코드를 express를 사용한 코드로 리팩토링하였다.

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const jsonParser = bodyParser.json({strict: false});

const app = express();
const port = 4999;
const defaultCorsHeader = {
  origin: "*",
  methods: "GET, POST, PUT, DELETE, OPTIONS",
  allowedHeaders: "Content-Type, Accept",
  maxAge: 10,
};

app.use(cors(defaultCorsHeader));
app.post("/upper", cors(), jsonParser, function (req, res) {
  const upperCase = req.body.toUpperCase();
  res.send(JSON.stringify(upperCase));
});
app.post("/lower", cors(), jsonParser, function (req, res) {
  const lowerCase = req.body.toLowerCase();
  res.send(JSON.stringify(LowerCase));
});

app.listen(port, () => {
  console.log(`Listening on port ${port}`);
});

위 코드를 작성하면서도 많은 시행착오와 검색이 필요했지만 재미있었다.
하나씩 알아낸 점들을 적어보자면...

pre flight를 위한 defaultCorsHeader를 보면 http 모듈을 쓸 때와는 조금 생긴게 다르다.
Access-Control-Allow-Origin 같은 길다란 것을 그냥 origin 이렇게 써도 된다는 점.

또 cors라는 미들웨어를 사용해 app.use(cors()) 와 같이 한꺼번에 모든 요청에 대해 CORS를 허용할 수 있다.
cors에 defaultCorsHeader 같은 것을 만들어 넣어주면 특정할 수 있는 것이고.
OPTIONS 메소드를 확인하고 응답하는 것이 필요없어졌다는 얘기다.

app.use는 미들웨어를 모든 요청에 적용할 수 있는 메소드이다.

다음은 body-parser인데 얘는 먼저 request.on().on() 이렇게 하면서 데이터를 변환시켜줘야 했던 과정을 또 알아서 처리해준다. 이 body-parser를 거친 데이터는 req.body에 예쁘게 들어가있게 된다.

그리고 마찬가지로 cors 미들웨어로 response에 writeHead를 작성하는 수고를 덜어준다.

응답을 보내주는 것은 end() 보다도 훨씬 알아보기 좋은 send()가 되었다.


그리고 언급되었던 미들웨어에 대하여..

미들웨어는 자동차가 만들어질 때 컨베이어 벨트 위에 뼈대가 올려지고 각 공정마다 부품이 추가되고 모든 부품이 추가되면 완성된 자동차가 나오고, 어딘가 문제가 있다면 불량품 처리가 되는 것처럼, 어떤 request가 들어왔을 때 이를 차례로 처리해주는 역할을 한다. 이 미들웨어는 express의 가장 큰 장점이다.

미들웨어를 사용하는 상황
1. 모든 요청에 대해 url이나 메소드를 확인할 때
2. POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
3. 모든 요청/응답에 CORS 헤더를 붙여야할 때
4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
등..

미들웨어를 사용하면 node.js만으로 구현한 서버에서는 다소 번거로울 수 있는 작업을 보다 쉽게 적용할 수 있다.
위에서 사용한 cors와 body-parser가 그 예시이다. 둘 다 사용하려면 npm i 미들웨어이름 으로 설치해야 한다.

1, 4번에 해당하는 예시는 직접 만들고 적용해보았다.

const logger = function (req, res, next) {
  console.log(`http request method is ${req.method}, url is ${req.url}`);
  next();
};

const checkToken = function (req, res, next) {
  if (req.headers.token) {
    req.isLoggedIn = true;
    next();
  } else {
    res.status(400).send("invalid user");
  }
};

두 함수에 있는 next()는 해당 미들웨어가 할 일을 마치면 다음 미들웨어로 넘어가도록 해주는 함수다.
req, res를 함께 넘겨주는 것이다. 이렇게 미들웨어를 만들었다면 app.use에 넣어 모든 요청에 적용하거나,

app.post("/upper", cors(), jsonParser, logger, checkToken, function (req, res){...});

이런 식으로 적용한다. checkToken이나 logger같은 것은 모든 요청에서 쓰일테니 app.use를 쓰는 편이 좋긴할 것 같다. 미들웨어는 당연히 적어준 순서대로 작동하는 것 같다.

좋은 웹페이지 즐겨찾기