🌐웹개발

Express.js

익스프레스

Node.js 웹 프레임워크. 미니멀리스트 설계. 미들웨어 기반 아키텍처.

📖상세 설명

Express.js는 2010년 출시된 Node.js의 사실상 표준 웹 프레임워크입니다. npm에서 주간 다운로드 3,000만 이상을 기록하며, Node.js 백엔드의 약 70%가 Express를 사용합니다. 미니멀하고 유연한 설계로 다양한 미들웨어를 조합해 원하는 기능을 구축할 수 있습니다.

핵심 개념은 미들웨어 체인입니다. 요청(req)과 응답(res)을 순차적으로 처리하며, next() 함수로 다음 미들웨어에 제어권을 넘깁니다. 로깅, 인증, CORS, 에러 처리 등 공통 로직을 미들웨어로 분리해 재사용할 수 있습니다.

Express 4.x는 오랫동안 안정 버전으로 유지되고 있으며, 5.x가 알파 단계입니다. 대규모 생태계 덕분에 passport(인증), multer(파일 업로드), helmet(보안), cors 등 거의 모든 기능의 미들웨어가 존재합니다. NestJS, Feathers 같은 상위 프레임워크도 Express를 기반으로 합니다.

단점으로는 TypeScript 지원이 네이티브가 아니고, 비동기 에러 처리가 번거로우며, 성능이 Fastify 등 후발 프레임워크 대비 낮습니다. 하지만 압도적인 생태계와 레퍼런스 덕분에 여전히 가장 널리 사용되는 선택지입니다.

💻코드 예제

// Express.js 미들웨어 기반 API 서버
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';

const app = express();

// 글로벌 미들웨어
app.use(helmet()); // 보안 헤더
app.use(cors({ origin: 'https://myapp.com' }));
app.use(express.json()); // JSON 파싱

// 커스텀 로깅 미들웨어
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
  next();
});

// 인증 미들웨어
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) {
    return res.status(401).json({ error: 'Token required' });
  }
  try {
    req.user = verifyToken(token);
    next();
  } catch {
    res.status(403).json({ error: 'Invalid token' });
  }
};

// 라우트 정의
app.get('/api/public', (req, res) => {
  res.json({ message: 'Public data' });
});

app.get('/api/protected', authMiddleware, (req, res) => {
  res.json({ user: req.user, message: 'Protected data' });
});

// 비동기 라우트 (Express 4.x에서는 try-catch 필요)
app.get('/api/users/:id', async (req, res, next) => {
  try {
    const user = await db.users.findById(req.params.id);
    if (!user) return res.status(404).json({ error: 'Not found' });
    res.json(user);
  } catch (error) {
    next(error); // 에러 미들웨어로 전달
  }
});

// 에러 처리 미들웨어 (4개 인자 필수)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Internal server error' });
});

app.listen(3000, () => console.log('Server running on :3000'));

🗣️실무 대화 예시

💼프로젝트 킥오프에서

"백엔드는 Express로 가려고 해요. 팀원들 대부분 Express 경험 있고, 필요한 미들웨어가 다 있어서 빠르게 MVP 만들 수 있습니다. 성능이 크리티컬해지면 그때 Fastify 마이그레이션 고려해도 늦지 않아요."

🎯기술 면접에서

"면접관: Express 미들웨어의 실행 순서를 설명해주세요.

지원자: app.use()로 등록된 순서대로 실행됩니다. 각 미들웨어는 next()를 호출해야 다음 미들웨어로 넘어가고, next()를 호출하지 않으면 체인이 멈춥니다. 에러 미들웨어는 4개 인자를 가지며, next(error) 호출 시 일반 미들웨어를 건너뛰고 에러 미들웨어로 갑니다."

🔍코드 리뷰에서

"async 라우트 핸들러에서 try-catch 없이 await 쓰고 있는데, Express 4.x는 프로미스 리젝션을 자동 캐치 안 해요. express-async-errors 패키지를 쓰거나 모든 async 핸들러를 try-catch로 감싸주세요."

⚠️주의사항

🔗관련 용어

📚더 배우기