개발자공부일기
Express 본문
Express란?
Express는 웹 및 모바일 애플리케이션을 위한 일련의 강력한 기능을 제공하는 간결하고 유연한 Node.js 웹 애플리케이션 프레임워크이다. 사실상 Nodejs의 표준 웹서버 프레임워크로 불려질 만큼 많은 곳에서 사용하고 있다. 그렇다면 Node.js와 Express는 무슨 관계인가?
Node.js는 Chrome의 V8엔진을 이용하여 javascript로 브라우저가 아니라 서버를 구축하고, 서버에서 JavaScript가 작동되도록 해주는 런타임 환경(플랫폼)이라고 했다. Express는 이런 Nodejs의 원칙과 방법을 이용하여 웹애플리케이션을 만들기 위한 프레임워크이다.
프레임워크란?
이처럼 목적에 필요한 것을 고민할 필요 없이 이용할 수 있도록 일괄로 가져다 쓰도록 만들어 놓은 '구조화된 틀'입니다.
왜 Express 를 사용할까?
Express는 프레임워크이므로 웹 애플리케이션을 만들기 위한 각종 라이브러리와 미들웨어 등이 내장돼 있어 개발하기 편하고, 수많은 개발자들에게 개발 규칙을 강제하여 코드 및 구조의 통일성을 향상시킬 수 있다. 그것이 바로 프레임워크 도입의 가장 큰 장점이다.
가장 많은 곳에서 보편적으로 사용되기 때문에 Express를 도입하면 구글링을 통해 충분한 레퍼런스들을 검색할 수 있다.
그럼 더 자세히 알아보자
────────────────
1. Express는 정확히 뭐냐?
────────────────
Express(Express.js)는 Node.js 위에서 돌아가는 HTTP 서버 프레임워크다.
즉 “브라우저/클라이언트의 요청을 받고 → 처리하고 → 응답을 돌려주는 웹 서버”를 편하게 만드는 도구.
Node.js만으로도 서버는 만들 수 있다. 하지만 Node.js 기본 http 모듈만 쓰면 모든 걸 직접 해야 한다.
예를 들어 다음을 직접해야 함:
- 어떤 URL로 왔는지 판별
- GET인지 POST인지 판별
- 요청 body(JSON인지 form인지 등) 직접 파싱
- 쿠키/헤더 분석
- CORS 같은 공통 정책
- try/catch로 에러 처리하고 적절한 status code 내려주기
- 같은 로직 반복 (로그 찍기, 인증 검사 등)
이걸 매번 수작업으로 하면 프로젝트가 5개 라우트만 넘어가도 코드가 금방 더러워진다.
Express는
이 반복 패턴을 표준화해 준 “얇은 레이어”라고 보면 된다.
즉
- 라우팅
- 미들웨어
- request/response 편의 기능
- 에러 처리 흐름
이 4개를 눈에 보이는 형태로 정리해 준 게 Express다.
────────────────
2. Express의 핵심 개념들
────────────────
(1) 라우팅 (Routing)
라우팅은 “어떤 요청을 어떤 함수가 처리할지 매핑해 주는 규칙”이다.
예: GET /users → 유저 목록 주는 함수
POST /login → 로그인 처리하는 함수
Express에서는 이렇게 쓴다:
const express = require('express');
const app = express();
app.get('/users', (req, res) => {
res.json([{ name: 'Alice' }]);
});
app.post('/login', (req, res) => {
// req.body 안에 클라이언트가 보낸 JSON 데이터가 있다 (아래에서 설명)
if (req.body.id === 'youmin' && req.body.pw === '1234') {
res.status(200).json({ ok: true, token: '...' });
} else {
res.status(401).json({ ok: false });
}
});
app.listen(3000);
여기서 중요한 점:
- if(req.url === '/users' && req.method === 'GET') 이런 원시 분기문을 내가 안 짜도 됨
- res.status(...).json(...) 같이 응답도 사람이 읽기 쉽게 표현 가능함
(2) 미들웨어 (Middleware)
미들웨어는 쉽게 말하면 “요청이 실제 핸들러에 도달하기 전에(또는 응답 보내기 전에) 거쳐가는 공용 필터/훅”이다.
형식은 거의 다 이런 모양이다:
function someMiddleware(req, res, next) {
// 1) 요청을 살펴본다 (ex: 토큰 확인)
// 2) req나 res에 정보를 추가해도 된다 (ex: req.user = {...})
// 3) 모든 게 정상이라면 next()를 호출해서 다음 단계로 넘긴다
// 4) 문제가 있으면 res.status(403).send('no') 로 여기서 끊어도 된다
next();
}
app.use(someMiddleware);
이걸 전역으로 깔면 모든 요청이 이 미들웨어를 거쳐 간다.
실전에서 자주 쓰는 미들웨어 예시:
- CORS 설정
- 로그인 여부 확인 (JWT 검증 등)
- 요청 로깅 (누가 언제 뭐 쳤는지)
- rate limiting (너무 많은 요청 막기)
- body 파서 (JSON 본문을 req.body에 넣어줌)
- 에러 핸들러
미들웨어의 장점은 “공통 정책을 한 군데에 모아서 재사용할 수 있다”는 거다.
팀 작업할 때 이건 엄청 중요하다.
(백엔드 코드를 if문으로 도배하지 않게 만들어 준다)
(3) req / res 확장
Express가 제공해주는 req, res 객체는 Node.js의 기본 요청/응답 객체를 감싼 것이다.
그래서 아래 같은 편의 기능이 생긴다.
- req.body → 이미 파싱된 요청 본문(JSON 등)
- req.params → 라우트 파라미터(/users/:id 처럼 URL 안의 값)
- req.query → 쿼리스트링(?page=2&limit=10 이런 거)
- res.status(201) → status code 설정
- res.json(data) → JSON을 자동으로 직렬화 + 헤더 설정 후 응답
- res.send(text) → 문자열/버퍼 등 보내기
이 편의 기능 덕분에, 로우 레벨 HTTP 헤더를 일일이 만질 필요가 줄어든다.
예:
app.get('/users/:id', (req, res) => {
const userId = req.params.id; // URL에서 뽑힘
const detail = req.query.detail; // ?detail=true 이런거
// DB에서 userId로 조회 ...
res.status(200).json({ id: userId, ... });
});
(4) 에러 처리 전용 미들웨어
Express는 “에러 처리 미들웨어”라는 특별한 패턴이 있다.
형태는 반드시 (err, req, res, next) 이렇게 4개의 인자를 받는다.
app.use((err, req, res, next) => {
console.error('서버 에러:', err);
res.status(500).json({ error: 'Server Error' });
});
장점:
- 라우트 코드마다 try/catch로 중복 처리하지 않고 한 군데에서 관리 가능
- 응답 포맷을 통일 가능 (예: 항상 {ok:false, message: "..."} 형태로 주자 등)
팀 규모가 커지면 에러 포맷 통일은 진짜 중요하다.
프론트엔드가 처리하기 쉬워지고, 운영 관제/로그 분석도 쉬워진다.
────────────────
3. Express를 채용하는 이유
────────────────
- 생산성
- JSON API 하나 만들자 → 라우트 한 줄, 미들웨어 몇 줄이면 바로 나온다.
- MVP(최소기능제품)나 해커톤, 사내 PoC(기술 검증용 프로토) 만들 때 속도가 빠르다.
- 구조화
- 라우터를 파일 단위로 쪼갤 수 있다.
- 기능별로 authRouter, postRouter, adminRouter 이런 식으로 쪼개고 app.use('/auth', authRouter) 이런 식으로 조립 가능하다.
- 즉 코드 구조를 모듈화하기 쉽다.
- 미들웨어 에코시스템
- 이미 만들어진 미들웨어가 엄청 많다.( Don't reinvent the wheel )
예: helmet(보안 헤더 세팅), cors(CORS 헤더 처리), morgan(로그), multer(파일 업로드), cookie-parser(쿠키 파싱), express-session(세션)
- 이미 만들어진 미들웨어가 엄청 많다.( Don't reinvent the wheel )
- Node.js의 비동기 + 논블로킹 I/O 모델과 잘 맞는다
- Express의 라우트 핸들러 안에서 DB 쿼리를 await 하고 있는 동안, Node.js 이벤트 루프는 다른 요청도 계속 받을 수 있다.
- 즉 동시 접속자 수가 많아도 비교적 적은 자원(CPU, 메모리)으로 처리 가능하다.
(물론 CPU를 엄청 갈아버리는 연산은 별도 워커로 빼야 한다. 그건 Express 문제가 아니라 Node.js 특성 문제)
- 학습 장벽이 낮다
- 스타트업/소규모 팀에서는 이게 큰 장점이다. (특히 온보딩 속도)
────────────────
4. Express를 쓰면 언제 좋은가?
────────────────
전형적인 상황:
- REST API 서버
- 간단한 백엔드 어드민 API
- 웹훅 수신 서버 (예: 결제 서비스에서 webhook 날려주는 거 받기)
- BFF(Backend For Frontend): 프론트 앱(웹/모바일)이 호출하는 가벼운 백엔드 게이트웨이
즉 “HTTP 요청 받고 JSON 뱉는 서버”가 필요하면 거의 다 Express로 시작할 수 있다.
────────────────
5. Express의 한계
────────────────
Express는 사실 굉장히 얇은 레이어다.
“앱 전체 아키텍처를 이렇게 구성해라”라고 강요하지 않는다.
이 말은 곧,
- 서비스가 커질수록 구조를 팀이 직접 정해야 한다.
- 컨트롤러 / 서비스 / 리포지토리 / DI(의존성 주입) / 계층형 아키텍처 / 모듈 경계 같은 것들을 전부 우리가 설계해야 한다.
- 테스트 전략(유닛/통합/엔드투엔드)도 팀이 정해야 한다.
- 대규모 팀에서 일관성이 떨어질 수 있다.
작을 땐 자유가 장점이다.
커지면 자유가 독이 된다.
이 지점에서 “Express는 가볍고 빠르지만, 규모가 커지면 관리가 어렵다”는 이야기가 나온다.
────────────────
6. Express의 대안들
────────────────
대안을 크게 3가지 레벨로 나눌 수 있다.
- Express랑 비슷한 레벨 (즉: 라우팅/미들웨어 프레임워크)
- 더 큰 프레임워크 (아키텍처까지 같이 제공)
(1) Express랑 비슷한 레벨
- Fastify
- 목표: 더 높은 성능, 더 일관된 구조, 더 엄격한 스키마 기반 개발.
- 장점 포인트
- 요청과 응답 스키마(JSON Schema)를 선언하면, 검증과 직렬화(응답 JSON 만드는 과정)를 고성능으로 자동화해준다.
- 속도 면에서 Express보다 더 효율적으로 하려고 많이 신경 쓴 구조.
- 팀에서 “우리는 트래픽 많을 거다”, “스키마 기반으로 API를 문서화하고 싶다” 이런 니즈가 있으면 Fastify를 선택하는 경우가 많다.
- Koa
- Express 팀 쪽 핵심 멤버들이 “한 세대 더 깔끔하게 다시 만들자” 해서 나온 철학의 프레임워크.
- 미들웨어가 async/await 기반으로 훨씬 모던하게 짜여 있다 (next() 호출 패턴이 깔끔).
- Express보다 더 미니멀하다. 정말 얇다.
그래서 “나는 진짜 커스텀 컨트롤 하고 싶어” 하는 사람에게 인기였다.
- Hapi
- 검증, 인증, 라우팅을 설정 기반으로(선언적으로) 다루는 스타일.
- 스타트업보다는 엔터프라이즈/내부 시스템에서 정책적으로 사용하는 경우가 많다.
- Express보다 “규칙적인 설정”을 선호하는 팀에 어울린다.
이 3개(Fastify, Koa, Hapi)는 결국 같은 문제를 푼다:
“HTTP 요청 들어왔을 때 누가 처리할지 정하고(JSON 라우트), 중간에 정책적 필터(미들웨어) 거는 문제”.
즉 Express의 직접적인 대체재라고 보면 된다.
(2) 더 큰 프레임워크 (아키텍처까지 같이 제공)
- NestJS
- NestJS는 그냥 라우터만 주는 게 아니라 “백엔드 애플리케이션의 뼈대”까지 같이 제공한다.
- 특징 키워드: 모듈, 컨트롤러, 서비스, 의존성 주입(DI), 데코레이터, 클래스 기반, TypeScript 중심.
- 즉 “Node.js 세계의 Spring 비슷한 거”라고 많이 설명한다.
- NestJS는 내부 어댑터로 Express(또는 Fastify)를 사용할 수 있다.
즉 NestJS는 Express 위에서 팀용 아키텍처를 덧씌운 상위 계층이라고 생각할 수도 있다.
- 팀원이 여러 명이고, 각자 마음대로 구조를 만들면 나중에 지옥일 것 같다.
- 서비스가 기능적으로 커질 게 확실하고, 관심사 분리(컨트롤러 / 서비스 / 리포지토리 / DTO 검증 등)가 필요하다.
- 테스트, 모듈화, 의존성 주입, 인터페이스 기반 개발 같은 걸 체계적으로 하고 싶다.
- Next.js (조금 성격이 다르지만 이제는 진지하게 경쟁)
- 원래는 React를 서버 사이드 렌더링(SSR)하기 위한 프레임워크로 유명하지만,
- 요즘은 Next.js 안에서 API 라우트나 server actions 같은 걸로 백엔드 로직도 같이 넣는다.
- 그러면 별도의 Express 서버 없이도 프론트(React)와 백엔드(API)가 한 프로젝트 안에서 돌아간다.
- “우린 프론트랑 백엔드가 사실상 붙어있고, 따로 배포 안 할 거야.”
- “BFF(Backend For Frontend) 정도만 있으면 돼.”
- “풀스택 1~2명이 거의 다 한다.”
이런 경우 Express 서버를 따로 띄우는 것보다 Next.js의 API 기능을 그냥 쓰는 게 더 단순하다.
────────────────
7. 요약 정리
────────────────
Express는 Node.js 위에서 HTTP 서버를 쉽게 만들 수 있게 해주는 경량 웹 프레임워크입니다.
핵심은 라우팅과 미들웨어 구조입니다.
라우팅은 URL/HTTP 메서드에 따라 어떤 컨트롤러 함수가 실행될지 선언적으로 매핑해주고,
미들웨어는 요청이 실제 핸들러에 도달하기 전이나 응답을 돌려주기 전에 공통 정책을 끼워넣는 레이어입니다.
예를 들어 인증 검사, 로깅, 에러 처리, CORS 설정 등을 미들웨어로 분리하면 모든 라우트에서 재사용이 가능합니다.
또한 Express는 req, res 객체에 편의 기능을 제공해서 본문 파싱, 응답 JSON 전송, 상태 코드 설정 등을 매우 간단하게 하게 해줍니다.
이 덕분에 Node.js의 기본 http 모듈을 직접 다루면서 if(req.url === ...) 같은 저수준 분기를 작성할 필요가 없어집니다.
실무에서 Express가 많이 쓰이는 이유는
- 생산성이 높고 (MVP나 PoC를 빠르게 만들 수 있음)
- 생태계가 넓어서 (CORS, 보안 헤더, 세션, 업로드 등 이미 있는 미들웨어를 바로 쓸 수 있음)
- Node.js의 비동기/논블로킹 I/O 모델과 맞물려서 적은 리소스로 많은 동시 요청을 처리할 수 있기 때문입니다.
하지만 Express는 매우 자유도가 높은 만큼, 서비스가 커졌을 때 아키텍처(계층 분리, 의존성 주입, 모듈 경계 등)를 강제하지 않습니다. 그래서 규모가 커지면 팀 내부 규칙이 없으면 코드 구조가 제각각이 되기 쉽습니다.
이런 한계를 보완하는 대안으로는,
- 같은 레벨의 대안: Fastify(성능과 스키마 기반 개발에 강함), Koa(더 모던한 미들웨어 스타일), Hapi(정책/설정 위주)
- 더 큰 프레임워크: NestJS(Express나 Fastify 위에 올라가는 구조화된 서버 프레임워크. 모듈/서비스/컨트롤러/DI 등 백엔드 전체 아키텍처를 표준화)
- 프론트와 백엔드를 한 덩어리로: Next.js의 API 라우트나 server actions (소규모 팀/초기 서비스에서 백엔드 따로 안 만들고 한 리포에 묶어 진행)
- Node.js 자체를 벗어나는 런타임: Deno, Bun 등 (표준 HTTP 핸들링과 TS 지원 등을 기본 제공해서 Express 같은 외부 프레임워크 의존도를 낮추려는 방향)
즉,
Express는 “Node.js로 웹 서버를 만들 때 사실상 표준으로 여겨지는 얇은 레이어”이고,
필요한 이유는 “반복되는 HTTP 처리 로직을 빠르고 일관성 있게 만들기 위해서”,
대안은 “더 성능 지향적인 Fastify/Koa/Hapi 같은 비슷한 급”과
“아키텍처까지 잡아주는 NestJS”,
“프론트와 API를 같이 품는 Next.js”,
“아예 다른 런타임(Deno/Bun)”까지 확장해서 볼 수 있다.
'Language > Javascript' 카테고리의 다른 글
| Arrow Function(화살표 함수) (0) | 2025.10.27 |
|---|---|
| Next.js에서 Node.js와 Edge환경 (0) | 2025.08.01 |
| Node.js의 Libuv 라이브러리 (0) | 2025.02.26 |
| Node.js의 이벤트 루프 (0) | 2025.02.20 |
| JWT (0) | 2025.02.11 |