[01 계층 분리의 필요성 ]
- 사실 1, 2차 프로젝트 때는 Controller 없이 3계층 구조로 크게는 Router / Service / DB로 나뉘고, route 방식으로는 Router와 Middleware만 사용했는데 이번 프로젝트에서 같은 백엔드 팀원의 제안으로 Router와 Middleware를 나누게 되었다.
- 일단 모든 코드를 나누지 않으면 어떤 엔드포인트로 접근했을 때 어떤 동작을 하게 되는지 한 눈에 볼 수 있어 유용할 수 있다. 그런데 조금만 기능이 복잡해지면 이런 방법으로 라우팅을 관리하는 것은 좋지 않다.
- 예를 들어 입력값을 검증하고 사용자가 로그인 한 뒤 기능을 수행하는 로직이 모두 Router 파일에 있으면 코드의 재생산성과 유지보수성이 현저히 떨어진다.
- 따라서 백엔드에서 정확한 계층 분리는 장기적으로 봤을 때 꼭 필요하다.
[02 Router / Controller / Middleware의 차이 ]
- Router : 엔드포인트와 해당 엔드포인트에서 실행돼야 할 로직을 연결해주는 역할
- Controller : Middleware의 일종이지만 메인 로직을 담당하므로 분리해서 관리
- Middleware : 메인 로직의 Controller 앞뒤로 추가적인 일을 담당
- 따라서 Router는 정말 코드의 전체적인 흐름, 경로만 나타내주고 Controller가 메인 로직을 담당(Service 계층으로 연결, Service는 DB계층으로 연결), Middleware는 그 외의 특별한 일을 함수로 따로 빼서 거치도록 해주는 느낌이다.
[03 코드에 적용 ]
(1) userRouter.ts
- 이렇게 라우터 파일은 입력값 정도만 검증하고 전체적인 흐름을 파악할 수 있도록 깔끔하게 관리한다.
import { Router } from "express";
import { UserController } from "../controllers/userController";
import { check } from "express-validator";
import { validatorErrorChecker } from "../middlewares/validator";
import { loginRequired } from "../middlewares/loginRequired";
const UserRouter = Router();
// 회원가입
UserRouter.post(
"/register",
[
check("user_name").exists(),
check("email").exists().isEmail(),
check("password").exists().isLength({ min: 8, max: 12 }),
validatorErrorChecker,
],
UserController.register,
);
// 로그인
UserRouter.post(
"/login",
[check("email").exists().isEmail(), check("password").exists().isLength({ min: 8, max: 12 }), validatorErrorChecker],
UserController.login,
);
// 회원 정보 수정
UserRouter.put("/updateInfo", loginRequired, UserController.updateInfo);
// 회원 탈퇴
UserRouter.delete("/withdrawal", loginRequired, UserController.withdrawal);
export { UserRouter };
(2) userController.ts
- 그리고 컨트롤러에서 입력값을 정제해서 서비스 계층의 함수에 넘겨주는 기능을 수행한다.
import { Request, Response, NextFunction } from "express";
import { UserService } from "../services/userService";
import { Users } from "../db/models/user";
import { IUserInput, IUserLoginInput, IUserInfoUpdateInput } from "../interfaces/userInput";
const UserController = {
register: async (req: Request, res: Response, next: NextFunction) => {
try {
const { user_name, email, password, gender, age_range, job }: IUserInput = req.body;
const newUser = await UserService.addUser({ user_name, email, password, gender, age_range, job });
res.status(201).json(newUser);
} catch (error) {
next(error);
}
},
.
.
.
}
- 원래 이 코드들이 다 라우터 파일에 들어있었는데 컨트롤러 파일로 분리하는 게 좋다는 것을 이번에 알게 되었다.
출처 : https://velog.io/@hiro2474/express-router-controller-middleware
'엘리스 AI트랙 4기 > 프로젝트' 카테고리의 다른 글
[TypeScript Express] Sequelize로 MySQL 모델 Association 관계 설정하기 (0) | 2022.06.15 |
---|---|
[TypeScript Express] Sequelize로 MySQL 기본 모델 생성하기 (0) | 2022.06.14 |
[Typescript Express] 로그인 로직에 JWT Token Middleware 적용하기 (0) | 2022.06.09 |
[Typescript Express] Sequelize로 MySQL 연결하기 (0) | 2022.06.08 |
Oracle Cloud 인스턴스에 MySQL 서버 구축_3탄 (2) | 2022.06.06 |