1. 미들웨어 중심의 아키텍처를 잘 활용하여야 한다.
- 요청과 응답 객체에 접근하고, 다음 미들웨어 호출 중심의 아키텍처를 잘 활용하여야 한다.
- 요청과 응답 객체에 접근하고, 다음 미들웨어 함수를 호출하는 ( next() ) 함수들의 연속으로 어플리이션의 로직이 구성된다.
- 기능분리
ㄴ 각 미들웨어는 하나의 명확한 기능을 담당하도록 작성해야한다. ( 로깅, 인증, 데이터파싱 ) 예를 들어서, 요청 본문을 파싱하는 express.json(), express.urlencoded()나 CORS를 처리하는 CORS 같은 미들웨어를 사용하는 것이 일반적이다.
- 실행 순서의 중요성
ㄴ 미들웨어는 app.use()나 라우터에 등록된 순서대로 실행된다. 따라서 인증 미들웨어는 항상 실제 로직을 처리하는 라우터보다 먼저 위치해야 한다. 순서가 잘못되면 의도치 않은 결과를 초래할 수 있다.
- 에러처리 미들웨어
ㄴ 일반 미들웨어와 다르게 에러처리 미들웨어는 (err, req, res, next) 4개의 인자를 가진다. 이 미들웨어는 모든 라우터와 미들웨어 체인의 가장 마지막에 위치시켜서 중앙에서 에러를 효과적으로 관리해야 한다.
// 1. 일반 미들웨어 ( 요청시간 로깅 )
app.use((req, res, next)=>{
console.log('Time:', Date.now());
next();
})
// 2. 라우터
app.use('/api/users', userRoutes);
// 3. 에러처리 미들웨어 ( 가장 마지막에 위치 )
app.use((err, req, res, next)=>{
console.error(err.stack);
res.status(500).send('Something broke!');
})
2. 라우터 분리
- 어플리케이션의 규모가 커지면 모든 라우트를 app.js 파일 하나에 관리하기 어렵다.
- express.Router를 사용해 기능별로 라우터 파일을 분리하는 것이 필수적이다.
ㄴ 관심사 분리 Separation of Concerns : 사용자 관련 api는 route/user.js, 상품 관련 api는 routes/product.js와 같이 도메인 별로 파일을 분리한다.
ㄴ 모듈화 : 각 라우트 파일은 express.Router 인스턴스를 생성하여 로직을 정의하고, 이를 모듈로 export 한다. 메인파일 app.js에서는 이 모듈들을 import 하여 특정 경로에 연결한다.
3. 비동기 처리와 에러 핸들링
- Node.js 환경상 비동기 작업이 많으므로, 이를 효과적으로 처리하는 것이 중요하다.
- Promise와 async/await 활용 : 콜백 지옥을 피하기 위해서 Promise나 async/await 문법을 적극적으로 사용해야한다. 이는 코드를 더 읽기 쉽고 동기적인 흐름처럼 보이게 해준다.
- 비동기에러처리 : async/await을 사용할 때 try...catch 블록으로 비동기 작업 중 발생할 수 있는 에러를 잡아 next(err)를 통해 에러처리 미들웨어로 전달해야 한다. 혹은 express-async-handler와 같은 라이브러리를 사용하면 이 과정을 자동화할 수 있다.
router.get('/:id', async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).send('User not found');
}
res.send(user);
} catch (err) {
next(err); // 에러를 중앙 에러 핸들러로 전달
}
});
4. 환경변수 관리
- 데이터베이스 접속정보, api 키 등 민감하거나 환경에 따라서 달라지는 설정 값들은 코드에 직접 하드코딩해서는 안된다.
- .env 파일 사용 : dotenv 라이브러리를 사용하여, .env 파일에 환경변수를 정의하고, process.env 객체를 통해 접근하는 것이 일반적이다. .env 파일은 .gitignore에 추가하여 Git 저장소에 올라가지 않도록 주의해야한다.
require('dotenv').config();
const port = process.env.PORT || 5000;
const mongoUri = process.env.MONGO_URI;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
5. MVC 패턴 활용
- Express 자체는 특정 아키텍처를 강요하지 않지만, MVC 패턴 또는 이와 유사한 구조를 적용하면 코드베이스를 체계적으로 구성할 수 있다.
ㄴ Controller : 라우트 핸들러의 로직이 길어지면 별도의 컨트롤러 함수로 분리한다. 컨트롤러는 요청을 받아서 비즈니스 로직 Service을 호출하고, 그 결과를 응답으로 보낸다.
ㄴ Service ( or Business Logic ) : 실제 어플리케이션의 핵심 비즈니스 로직을 담당한다. 데이터베이스 모델과 상호작용하고, 복잡한 계산 등을 처리한다.
ㄴ Model : 데이터베이스 스키마를 정의하고 데이터에 접근하는 계층이다.
'Backend > Node.js' 카테고리의 다른 글
Passport 인증 미들웨어 (0) | 2025.04.22 |
---|---|
[Express] 정리 (1) (0) | 2025.04.10 |