
이전 2차 프로젝트를 회고하면서
미들웨어에 대해서 조금 더 관심이 생겼다
이 부분에 대해서 조금 더 다뤄보려고 한다!
바로 시작을 해보자!
API는 요청이 들어왔을 때부터
응답으로 내보내기까지의 전 과정을 처리하는데
이때 레이어드 패턴을 기준으로
app.js -> route -> controller -> service -> model
순으로 요청 및 데이터가 들어왔다가 다시 역순으로 올라가 응답을 보낸다고 했었다
미들웨어는 저 한계의 단과 단을 의미하는 것이 아닌
단과 단 사이에서 일을 하는 함수이다!

이런식으로 각 단에 넘어가는 중간단계에 있는 함수!라고 생각하면 되겠다!
그럼 대표적인 미들웨어를 한번 알아보자!
아마 아는 사람도 많을테지만 주입식으로 교육받은 사람들은(대표적으로 나)
그 쓰임새를 잘 모르고 넘어갈 수도 있는 부분이다!
우리는 자연스럽게 데이터를 주고 받을 때 res.json으로 주거나
포스트맨에서 데이터를 줄 때 raw-json으로 body값을 보냈을 것이다
하지만 기본적인 http의 특성상
모든 값들은 일반적인 string으로 전송이 된다!
이렇게 string의 데이터를
받기 전이나 주기 전에 json형태로 변환을 하는 과정이 있었다
이 기능은 express의 미들웨어 중 하나인 json을 통해서 이뤄진다!
간단하게 코드를 보자면
const express = require('express')
const app = express()
app.use(express.json())
app.get('/user/list', allUserList)
...
이렇게 라우트를 선언하기전에 express와 그 미들웨어인 json을 실행해줌으로서
request로 들어오는 모든 string데이터를 json형식으로 받을 수 있게끔 해주면 된다!

우리가 처음으로 프론트엔드와 통신을 할 때
의미를 잘 모르고 썼던 라이브러리 중 하나일텐데, CORS는 브라우저의 보안정책이다
기본적으로 통신을 할 때에는 같은 출처(origin)에서 접근을 했을 때
해당 API를 호출할 수 있는데 이 세팅을 맞추는 것이 쉽지가 않다
(원래 확실히 알아야 하는건 어렵다..)
그래서 브라우저의 모든 요청에 대해서 개방되어있는 상태를 두는 방법이 있다
이 세팅도 쉽지는 않지만 다행히도 express의 라이브러리로 제공되고 있다!
일단 설치!
npm install cors
이후 간단하게 코드를 보자면
const express = require('express')
const app = express()
app.use(cors())
...
이 정도의 세팅만 하면(가장 기본적인 세팅이다)
모든 출처(origin)에 대해서
GET, PUT, .. , DELETE 등의 모든 메서드를 허용한다는 세팅이 되었다고 보면된다!
이후 내 IP주소를 알려주면 프론트가 알아서 연결을 시도 할 것이다!
(이후 배포 단계에서는 이렇게 모든걸 열어두면 안되는 이부분은 따로 포스팅 해보겠다!)
사실 이 부분을 위해서 빌드업을 했다고 볼 수 있는데
이전에 포스팅 했던 JWT의 payload에 대한 위험성에 대한 보충 자료이자
2차 프로젝트에 대한 반성 부분이 있기 때문이다
payload는 탈취되었을 경우 아주 쉽게 뚫리기 때문에
(사실 탈취되는 경우가 많이 없지만 그런 경우가 생긴다면 위험하니까)
아주 필요한 정보만 암호화 해서 담아야 한다고 얘기를 했었다
그럼 payload에 담았던 아주 좋은 정보들(이메일, 주소, 전화번호 등등)은
이제 못 쓰니 아주 귀찮아졌다고 생각을 할 수도 있다!
하지만 이에 대비한 미들웨어를 만듦으로서 대비를 할 수 있다!
한번 해보자!
// src/routes/userRouter.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const auth = require('../middleware/auth');
// /user/info 로 들어온 리퀘스트를 두 개의 함수로 받는다
// 첫번째 함수는 유저 검증, 두번째 함수는 이후 컨트롤러 단으로 넘어가는 함수
router.get('/info', auth.loginRequired, userController.userInfo )
module.exports = {
router
}
이렇게 라우트 단에서 두개의 함수를 넣고
// src/middleware/auth.js
const jwt = require('jsonwebtoken');
const userDao = require('../models/userDao');
const secretKey = process.env.TYPEORM_SECRET_KEY
const loginRequired = async (req, res, next) => {
try {
const accessToken = req.headers.authorization.substr(7);
if (!accessToken) {
const error = new Error('NEEDED_ACCESS_TOKEN');
error.statusCode = 401;
throw error
}
const payload = jwt.verify(accessToken, secretKey);
const userData = await userDao.getUserById(payload.Id);
console.log(userData)
// {
// id : 345,
// naem : '김봉구',
// email : 12345@git.com,
// gender : female,
// address : '서울시 서초구 효령로 234 202호'
// }
if (!userData) {
const error = new Error('USER_DOES_NOT_EXIST');
error.statusCode = 404;
throw error
}
req.userData = userData;
next();
} catch(err) {
res.status(err.statusCode || 500)
.json({message: err.message || 'INTERNAL_SERVER_ERROR'})
}
}
module.exports = {
loginRequired
}
이렇게 미들웨어 함수를 짜면
next()함수를 통해 loginRequired함수의 과정을 끝낸 뒤
req에 userData라는 데이터를 담아서 userRouter.js로 돌아가
다음 함수인 userController.userInfo로 데이터를 넘기는 것이다
이렇게 되면 두가지 경우가 생기는데
이렇게 불필요한 컨트롤러단의 진입을 막고
토큰검증이 완료되면 다음 단에서 쓰일 유저 데이터를
미리 req에 심어서 보내는게 가능해지므로
각 파트별 백엔드들에게 필요한 데이터를 묻고 그 데이터를 종합해
미들웨어를 만들면 아주 유용하게 쓰일 수 있게 될 것이다!
이렇게 미들웨어의 필요성과 몇가지 예시를 함께 알아보았다!
개념 자체는 간단할 수 있는데 막상 만들려다보니 한참을 헤멨는데
이번에 다시 정리해보면서 나도 조금은 더 확실히 알게 된 것 같아
기분이 좋았다!
난 미들웨어의 대표적인 예시만 들었고
실제로 아직까지는 저 3가지 정도 밖에 모르는데
다른 사람의 깃헙을 보다 보면 실로 여러가지의 미들웨어를 사용하는 것을 볼 수 있었다!
(아직 이해는 잘되지 않지만)
여러분도 다양한 미들웨어를 만들어보시길..!
++
발돋움 중인 예비 개발자 입니다.
태클 및 의견 공유 언제나 환영 :D