728x90
반응형
1. Express.js란
Express.js는 Node.js를 위한 가장 인기 있는 웹 프레임워크입니다. 미니멀하고 유연한 설계로 웹 애플리케이션과 API를 빠르게 구축할 수 있습니다.
npm install express
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('서버 실행 중: http://localhost:3000');
});
2. 라우팅
2.1 기본 라우팅
const express = require('express');
const app = express();
// HTTP 메서드별 라우트
app.get('/', (req, res) => {
res.send('GET 요청');
});
app.post('/users', (req, res) => {
res.send('POST 요청');
});
app.put('/users/:id', (req, res) => {
res.send('PUT 요청');
});
app.delete('/users/:id', (req, res) => {
res.send('DELETE 요청');
});
// 모든 HTTP 메서드
app.all('/api/*', (req, res, next) => {
console.log('API 요청:', req.method, req.path);
next();
});
app.listen(3000);
2.2 라우트 파라미터
// 경로 파라미터
app.get('/users/:userId', (req, res) => {
const userId = req.params.userId;
res.send(`사용자 ID: ${userId}`);
});
// 여러 파라미터
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.send(`사용자 ${userId}의 포스트 ${postId}`);
});
// 선택적 파라미터
app.get('/posts/:year/:month?', (req, res) => {
const { year, month } = req.params;
res.send(`${year}년 ${month || '전체'}월`);
});
// 정규표현식 파라미터
app.get('/users/:id(\\d+)', (req, res) => {
// id가 숫자일 때만 매칭
res.send(`사용자 ID: ${req.params.id}`);
});
2.3 라우터 모듈화
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.json([{ id: 1, name: '홍길동' }]);
});
router.get('/:id', (req, res) => {
res.json({ id: req.params.id, name: '홍길동' });
});
router.post('/', (req, res) => {
res.status(201).json({ id: 2, ...req.body });
});
module.exports = router;
// app.js
const express = require('express');
const userRoutes = require('./routes/users');
const app = express();
app.use('/users', userRoutes);
app.listen(3000);
3. 미들웨어
3.1 미들웨어 기본
const express = require('express');
const app = express();
// 애플리케이션 레벨 미들웨어
app.use((req, res, next) => {
console.log('요청 시간:', Date.now());
next(); // 다음 미들웨어로
});
// 특정 경로에만 적용
app.use('/api', (req, res, next) => {
console.log('API 요청');
next();
});
// 여러 미들웨어 체인
app.use('/admin', authenticate, authorize, (req, res) => {
res.send('관리자 페이지');
});
function authenticate(req, res, next) {
// 인증 로직
next();
}
function authorize(req, res, next) {
// 권한 검사
next();
}
app.listen(3000);
3.2 내장 미들웨어
const express = require('express');
const app = express();
// JSON 파싱
app.use(express.json());
// URL 인코딩된 본문 파싱
app.use(express.urlencoded({ extended: true }));
// 정적 파일 서빙
app.use(express.static('public'));
app.use('/static', express.static('files'));
// raw 본문 파싱
app.use(express.raw({ type: 'application/octet-stream' }));
// 텍스트 본문 파싱
app.use(express.text({ type: 'text/plain' }));
3.3 서드파티 미들웨어
const express = require('express');
const morgan = require('morgan'); // 로깅
const cors = require('cors'); // CORS
const helmet = require('helmet'); // 보안 헤더
const compression = require('compression'); // 압축
const app = express();
app.use(helmet()); // 보안 헤더 설정
app.use(cors()); // CORS 허용
app.use(compression()); // 응답 압축
app.use(morgan('combined')); // 요청 로깅
// CORS 상세 설정
app.use(cors({
origin: ['http://localhost:3000', 'https://example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true
}));
app.listen(3000);
3.4 에러 처리 미들웨어
const express = require('express');
const app = express();
app.get('/error', (req, res, next) => {
next(new Error('의도적 에러'));
});
// 비동기 에러 처리
app.get('/async-error', async (req, res, next) => {
try {
await someAsyncOperation();
res.send('성공');
} catch (err) {
next(err);
}
});
// Express 5에서는 자동 처리
app.get('/async-error2', async (req, res) => {
await someAsyncOperation(); // 에러 시 자동으로 에러 핸들러로
res.send('성공');
});
// 404 핸들러
app.use((req, res, next) => {
res.status(404).json({ error: 'Not Found' });
});
// 에러 핸들러 (4개의 인자)
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Internal Server Error'
});
});
app.listen(3000);
반응형
4. 요청과 응답
4.1 요청 객체 (req)
app.post('/users', (req, res) => {
// 요청 정보
console.log(req.method); // POST
console.log(req.path); // /users
console.log(req.originalUrl); // /users?page=1
console.log(req.protocol); // http
console.log(req.hostname); // localhost
console.log(req.ip); // 127.0.0.1
// 파라미터
console.log(req.params); // { id: '123' }
console.log(req.query); // { page: '1' }
console.log(req.body); // { name: '홍길동' }
// 헤더
console.log(req.headers); // 전체 헤더
console.log(req.get('Content-Type')); // 특정 헤더
// 쿠키 (cookie-parser 필요)
console.log(req.cookies);
res.send('OK');
});
4.2 응답 객체 (res)
app.get('/response-examples', (req, res) => {
// 상태 코드
res.status(200);
res.status(404);
res.status(500);
// 헤더 설정
res.set('X-Custom-Header', 'value');
res.set({
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
});
// 쿠키 설정
res.cookie('name', 'value', {
maxAge: 900000,
httpOnly: true,
secure: true
});
// 다양한 응답
res.send('텍스트 응답');
res.json({ message: 'JSON 응답' });
res.sendFile('/path/to/file.pdf');
res.download('/path/to/file.pdf', 'download-name.pdf');
res.redirect('/other-page');
res.redirect(301, '/permanent-redirect');
// 체이닝
res.status(201).json({ created: true });
});
4.3 다양한 응답 타입
// JSON 응답
app.get('/api/users', (req, res) => {
res.json({ users: [] });
});
// HTML 응답
app.get('/page', (req, res) => {
res.send('<h1>Hello</h1>');
});
// 파일 다운로드
app.get('/download', (req, res) => {
res.download('./files/report.pdf');
});
// 스트리밍 응답
app.get('/stream', (req, res) => {
res.setHeader('Content-Type', 'text/plain');
res.write('첫 번째 청크\n');
setTimeout(() => res.write('두 번째 청크\n'), 1000);
setTimeout(() => res.end('완료'), 2000);
});
// 리다이렉트
app.get('/old-page', (req, res) => {
res.redirect(301, '/new-page');
});
5. 템플릿 엔진
5.1 EJS 설정
const express = require('express');
const app = express();
// 뷰 엔진 설정
app.set('view engine', 'ejs');
app.set('views', './views');
app.get('/', (req, res) => {
res.render('index', {
title: '홈페이지',
users: [
{ name: '홍길동', age: 30 },
{ name: '김철수', age: 25 }
]
});
});
app.listen(3000);
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<ul>
<% users.forEach(user => { %>
<li><%= user.name %> (<%= user.age %>세)</li>
<% }) %>
</ul>
</body>
</html>
6. 실전 API 서버
const express = require('express');
const app = express();
// 미들웨어
app.use(express.json());
// 데이터 저장소
const users = new Map();
let nextId = 1;
// CRUD API
app.get('/api/users', (req, res) => {
const { page = 1, limit = 10 } = req.query;
const allUsers = Array.from(users.values());
const start = (page - 1) * limit;
const paginatedUsers = allUsers.slice(start, start + Number(limit));
res.json({
data: paginatedUsers,
total: allUsers.length,
page: Number(page),
limit: Number(limit)
});
});
app.get('/api/users/:id', (req, res) => {
const user = users.get(Number(req.params.id));
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'Name and email required' });
}
const user = { id: nextId++, name, email, createdAt: new Date() };
users.set(user.id, user);
res.status(201).json(user);
});
app.put('/api/users/:id', (req, res) => {
const id = Number(req.params.id);
const user = users.get(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const updated = { ...user, ...req.body, id };
users.set(id, updated);
res.json(updated);
});
app.delete('/api/users/:id', (req, res) => {
const id = Number(req.params.id);
if (!users.has(id)) {
return res.status(404).json({ error: 'User not found' });
}
users.delete(id);
res.status(204).end();
});
// 에러 핸들러
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(3000, () => {
console.log('API 서버 실행 중');
});
7. 프로젝트 구조
project/
├── src/
│ ├── controllers/
│ │ └── userController.js
│ ├── routes/
│ │ ├── index.js
│ │ └── userRoutes.js
│ ├── middleware/
│ │ ├── auth.js
│ │ └── errorHandler.js
│ ├── models/
│ │ └── User.js
│ ├── services/
│ │ └── userService.js
│ └── app.js
├── config/
│ └── index.js
├── public/
├── views/
└── package.json
// src/app.js
const express = require('express');
const routes = require('./routes');
const errorHandler = require('./middleware/errorHandler');
const app = express();
app.use(express.json());
app.use('/api', routes);
app.use(errorHandler);
module.exports = app;
// src/routes/index.js
const express = require('express');
const userRoutes = require('./userRoutes');
const router = express.Router();
router.use('/users', userRoutes);
module.exports = router;
// src/controllers/userController.js
const userService = require('../services/userService');
exports.getAll = async (req, res, next) => {
try {
const users = await userService.findAll();
res.json(users);
} catch (err) {
next(err);
}
};
exports.getById = async (req, res, next) => {
try {
const user = await userService.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: 'Not found' });
}
res.json(user);
} catch (err) {
next(err);
}
};
8. 유용한 팁
8.1 비동기 핸들러 래퍼
// 비동기 에러 자동 처리
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get('/users', asyncHandler(async (req, res) => {
const users = await User.findAll();
res.json(users);
}));
8.2 요청 검증
const { body, validationResult } = require('express-validator');
app.post('/users',
body('email').isEmail(),
body('password').isLength({ min: 6 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 처리
}
);
결론
Express.js는 Node.js 웹 개발의 사실상 표준 프레임워크입니다. 미들웨어 기반 아키텍처로 유연하게 기능을 추가할 수 있고, 라우팅, 요청/응답 처리, 에러 핸들링 등 웹 서버에 필요한 기능을 간결하게 구현할 수 있습니다. 프로덕션 환경에서는 helmet, cors, compression 등의 미들웨어와 함께 사용하고, 적절한 에러 처리와 로깅을 구현해야 합니다.
728x90
반응형
'Node.js' 카테고리의 다른 글
| Node.js의 HTTP 클라이언트 만들기 (0) | 2026.03.08 |
|---|---|
| Node.js의 Koa.js 프레임워크 (0) | 2026.03.08 |
| Node.js의 HTTP 서버 만들기 (0) | 2026.03.08 |
| Node.js의 파일 스트림 처리 (0) | 2026.03.07 |
| Node.js의 디렉토리 생성 및 삭제 (0) | 2026.03.07 |