본문 바로가기
JavaScript & TypeScript

Express.js 미들웨어의 역할 (TypeScript 버전)

by 대박플머 2024. 11. 19.

Express.js는 Node.js를 기반으로 하는 웹 프레임워크로, 라우팅, 미들웨어 관리, 요청 및 응답 처리 등의 기능을 제공합니다. 그중 미들웨어는 Express.js의 핵심 개념으로, 애플리케이션의 요청-응답 주기에 관여하는 코드 조각입니다. 이 글에서는 미들웨어의 역할, 종류, 그리고 TypeScript로 미들웨어를 작성하는 방법에 대해 자세히 알아보겠습니다.


1. 미들웨어란 무엇인가?

미들웨어는 HTTP 요청과 응답 사이에서 특정 작업을 수행하는 함수입니다. 클라이언트 요청이 들어오면 미들웨어는 이를 처리하고 다음 단계로 넘어가거나 응답을 종료할 수 있습니다. 미들웨어는 아래와 같은 특징을 가집니다.

  • 요청 및 응답 객체에 접근: req, res 객체를 통해 요청 데이터와 응답을 조작할 수 있습니다.
  • 다음 미들웨어로 제어 전달: next() 함수를 호출하여 다음 미들웨어로 제어를 넘깁니다.
  • 요청-응답 주기 종료: 응답을 종료하거나 오류를 처리할 수 있습니다.

2. 미들웨어의 종류

Express.js에서 미들웨어는 다음과 같이 다양한 종류로 분류됩니다.

  • 애플리케이션 레벨 미들웨어: app.use() 또는 app.METHOD()를 사용하여 애플리케이션 전반에 적용되는 미들웨어입니다.
  • 라우터 레벨 미들웨어: express.Router()를 사용하여 특정 라우터에만 적용되는 미들웨어입니다.
  • 내장 미들웨어: Express.js에 기본적으로 포함된 미들웨어로, express.json()이나 express.static()과 같은 기능이 있습니다.
  • 타사 미들웨어: morgan, body-parser 등과 같이 npm 패키지로 설치하여 사용하는 미들웨어입니다.
  • 오류 처리 미들웨어: 네 개의 인자 (err, req, res, next)를 가지며 오류를 처리하기 위한 목적으로 사용됩니다.

3. TypeScript로 미들웨어 작성하기

TypeScript를 사용하여 미들웨어를 작성하면 더 안전하고 예측 가능한 코드를 작성할 수 있습니다. 이제 기본적인 미들웨어를 TypeScript로 작성하는 예제를 살펴보겠습니다.

3.1. 기본 미들웨어 예제

먼저 간단한 로깅 미들웨어를 작성해 보겠습니다.

import { Request, Response, NextFunction } from "express";

// 로깅 미들웨어
const loggerMiddleware = (
  req: Request, // 클라이언트의 요청 정보를 담고 있는 객체
  res: Response, // 서버의 응답을 생성하는 객체
  next: NextFunction // 다음 미들웨어로 제어를 넘기는 함수
): void => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  next();
};

export default loggerMiddleware;

이 미들웨어는 요청이 들어올 때마다 현재 시간, HTTP 메서드, URL을 콘솔에 출력하고 next()를 호출하여 다음 미들웨어로 요청을 넘깁니다.

3.2. 애플리케이션 레벨 미들웨어 등록

위에서 작성한 미들웨어를 애플리케이션 레벨에서 사용하는 방법은 다음과 같습니다.

import express from "express";
import loggerMiddleware from "./middlewares/loggerMiddleware";

const app = express();

// app.use() 메서드는 미들웨어를 애플리케이션에 등록합니다.
// 첫 번째 인자로 미들웨어 함수를 받습니다.
// 이 미들웨어는 모든 HTTP 요청에 대해 실행됩니다.
app.use(loggerMiddleware);

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

app.use()를 통해 loggerMiddleware를 애플리케이션 레벨에 등록했습니다. 이로 인해 모든 요청에 대해 로깅이 수행됩니다.

3.3. 라우터 레벨 미들웨어

특정 경로에만 미들웨어를 적용하려면 라우터 레벨에서 사용할 수 있습니다.

import express, { Router, Request, Response } from "express";
import loggerMiddleware from "./middlewares/loggerMiddleware";

const app = express();
const userRouter: Router = Router();

// router.use([path], [function, ...] function)
userRouter.use(loggerMiddleware);

userRouter.get("/profile", (req: Request, res: Response) => {
  res.send("User Profile");
});

app.use("/user", userRouter);

app.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

위 코드에서는 /user/profile 경로에 접근할 때만 loggerMiddleware가 실행됩니다.

4. 오류 처리 미들웨어

오류 처리 미들웨어는 네 개의 인자 (err, req, res, next)를 받습니다. 오류 처리 미들웨어의 간단한 예제는 다음과 같습니다.

import { Request, Response, NextFunction } from "express";

// 오류 처리 미들웨어
const errorHandlerMiddleware = (
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  console.error(err.stack);
  res.status(500).json({ message: "Something went wrong!" });
};

export default errorHandlerMiddleware;

오류 처리 미들웨어는 app.use()를 통해 가장 마지막에 등록해야 합니다.

import express from "express";
import errorHandlerMiddleware from "./middlewares/errorHandlerMiddleware";

const app = express();

app.get("/", (req, res) => {
  throw new Error("Error occurred!");
});

app.use(errorHandlerMiddleware);

app.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

미들웨어의 위치는 애플리케이션의 요청-응답 주기에서 미들웨어가 실행되는 순서를 결정합니다. Express.js 애플리케이션에서 미들웨어는 app.use() 메서드를 통해 등록됩니다. 등록된 순서대로 미들웨어가 실행되며, 각 미들웨어는 다음 미들웨어로 요청을 전달하거나 응답을 반환할 수 있습니다.

예를 들어, 로깅 미들웨어를 애플리케이션의 시작 부분에 등록하면 모든 요청에 대한 로그를 기록할 수 있습니다. 반면, 오류 처리 미들웨어는 애플리케이션의 마지막에 등록해야 합니다. 이렇게 하면 모든 미들웨어에서 발생하는 오류를 처리할 수 있습니다.

따라서, 미들웨어의 위치는 애플리케이션의 로직과 기능에 직접적인 영향을 미칩니다. 적절한 위치에 미들웨어를 등록하면 애플리케이션의 성능과 안정성을 향상시킬 수 있습니다.

5. 미들웨어의 활용 사례

  • 인증 및 권한 부여: 사용자의 인증 상태를 확인하거나 특정 권한이 있는지 검증할 때 사용합니다.
  • 요청 데이터 파싱: JSON, URL 인코딩된 데이터 등을 파싱하는 데 사용됩니다. 예: express.json(), express.urlencoded().
  • 로깅: 요청 정보를 로깅하는 데 사용합니다.
  • 정적 파일 제공: 정적 파일을 제공할 때 express.static() 미들웨어를 사용합니다.

6. 미들웨어 작성 시 주의사항

  • 순서: 미들웨어는 등록된 순서대로 실행되므로 필요한 순서대로 설정해야 합니다.
  • next() 호출: next()를 호출하지 않으면 요청이 다음 미들웨어로 넘어가지 않고 멈춥니다.
  • 오류 처리 미들웨어의 위치: 항상 마지막에 등록해야 정상적으로 작동합니다.

7. 결론

Express.js에서 미들웨어는 애플리케이션의 요청-응답 주기를 효율적으로 관리하고 확장하는 데 핵심적인 역할을 합니다. TypeScript를 활용하면 타입 안전성과 코드 가독성을 높일 수 있어 더 유지보수하기 좋은 코드를 작성할 수 있습니다. 미들웨어를 제대로 이해하고 적절하게 활용하면 더욱 견고한 Express.js 애플리케이션을 구축할 수 있을 것입니다.

Express.js에서 유용한 모듈 5개를 추천합니다. 이들 모듈은 애플리케이션의 기능을 확장하고 유지보수를 용이하게 합니다.

  1. express-validator: 요청 데이터의 유효성을 검증하는 데 사용됩니다. 이를 통해 더욱 안전한 애플리케이션을 구축할 수 있습니다.
  2. cors: Cross-Origin Resource Sharing(CORS)를 처리하는 데 사용됩니다. 이를 통해 다른 도메인에서의 요청을 허용하거나 거부할 수 있습니다.
  3. helmet: 보안 관련 HTTP 헤더를 설정하는 데 사용됩니다. 이를 통해 애플리케이션의 보안을 강화할 수 있습니다.
  4. morgan: 요청에 대한 로그를 기록하는 데 사용됩니다. 이를 통해 애플리케이션의 동작을 추적하고 디버깅을 용이하게 합니다.
  5. compression: 응답 데이터를 압축하는 데 사용됩니다. 이를 통해 네트워크 대역폭을 절약하고 애플리케이션의 성능을 향상시킬 수 있습니다.

이러한 모듈을 적절히 활용하면 Express.js 애플리케이션의 기능을 확장하고 유지보수를 용이하게 할 수 있습니다. Express.js를 사용하는 개발자라면 이러한 모듈을 적극적으로 활용해보세요.