클라이언트가 요청을 보내면 서버는 반드시 응답을 돌려줘야 한다. Express에서 그 역할을 담당하는 것이 Response 객체, 즉 res다. res는 HTTP 응답의 상태 코드, 헤더, 본문을 모두 제어하는 인터페이스이며, 메서드를 체이닝해 간결하게 응답을 구성할 수 있다.
Client Express Router Handler
│ │ │
│── GET /users ───>│ │
│ │── req, res ─────>│
│ │ │── res.status(200).json(data)
│<─ 200 JSON ──────────────────────────
Route Handler가 res 메서드를 호출하는 순간 응답이 전송된다. 이후 추가 res 호출은 "headers already sent" 오류를 발생시키므로 핸들러당 정확히 한 번 응답해야 한다.
가장 범용적인 응답 메서드다. 인자 타입에 따라 Content-Type을 자동으로 결정한다.
app.get('/ping', (req, res) => {
res.send('pong'); // text/html
// res.send({ ok: true }); // application/json (객체 전달 시)
// res.send(Buffer.from('...')); // application/octet-stream
});
응답 본문을 JSON으로 직렬화하고 Content-Type: application/json을 설정한다. API 서버에서는 res.send 대신 res.json을 명시적으로 사용하는 것이 관례다.
app.get('/users/:id', (req, res) => {
const user = { id: req.params.id, name: 'Alice' };
res.json(user);
});
HTTP 상태 코드를 설정한다. 단독으로는 응답을 전송하지 않으며 반드시 다른 메서드와 체이닝해야 한다.
app.post('/users', (req, res) => {
const created = { id: 42, ...req.body };
res.status(201).json(created);
});
app.delete('/users/:id', (req, res) => {
res.status(204).send();
});
204 No Content — 본문 없이 성공을 알릴 때 사용하는 상태 코드.
클라이언트를 다른 URL로 이동시킨다. 기본 상태 코드는 302(임시 리다이렉트)이며 첫 번째 인자로 변경할 수 있다.
app.get('/old-path', (req, res) => {
res.redirect(301, '/new-path');
});
파일을 응답으로 전송한다. sendFile은 인라인으로 열리고, download는 브라우저가 파일 저장 다이얼로그를 띄운다.
import path from 'path';
app.get('/report', (req, res) => {
const filePath = path.resolve(__dirname, 'files/report.pdf');
res.download(filePath, 'monthly-report.pdf');
});
| 메서드 | Content-Type 자동 설정 | 응답 전송 | 주요 용도 |
|---|---|---|---|
res.send | O (타입 추론) | O | 범용 |
res.json | application/json | O | API 응답 |
res.status | X | X | 상태 코드 설정 |
res.redirect | text/html | O | URL 이동 |
res.sendFile | 파일 확장자 기반 | O | 정적 파일 서빙 |
res.download | application/octet-stream | O | 파일 다운로드 |
res.status는 res 자신을 반환하기 때문에 체이닝이 가능하다. 실전에서는 아래 패턴이 가장 많이 쓰인다.
// 성공
res.status(200).json({ data });
// 클라이언트 오류
res.status(400).json({ error: 'Invalid input' });
// 서버 오류
res.status(500).json({ error: 'Internal server error' });
상태 코드를 생략하면 기본값 200이 적용된다. 명시적으로 코드를 표현하는 습관이 코드 가독성과 디버깅 양쪽에 유리하다.