안녕하세요! 오늘은 제가 개발한 DevStudy Mate 프로젝트에서 기존에 Next.js에 통합되어 있던 서버 기능을 별도의 Express 서버로 분리하게 된 이유와 과정을 공유하려고 합니다.
Express는 Node.js 환경에서 실행되는 웹 애플리케이션 프레임워크입니다. 미니멀하고 유연한 특성을 가지고 있어, 웹 애플리케이션과 API를 개발하기 위한 강력한 기능을 제공합니다. Node.js의 http 모듈 위에 구축되어 있으며, 라우팅, 미들웨어 구성, 템플릿 엔진 통합 등 웹 서버 개발에 필요한 다양한 기능을 쉽게 사용할 수 있게 해줍니다.
가장 결정적인 이유 중 하나는 Next.js의 API 라우트를 사용했을 때 발생한 타임아웃 이슈였습니다. 코드 분석을 위해 OpenAI API를 호출하는 과정에서 처리 시간이 길어지면 504(Gateway Timeout) 또는 502(Bad Gateway) 에러가 발생했습니다.
Vercel이나 다른 서버리스 플랫폼에서 호스팅되는 Next.js API 라우트는 일반적으로 10~60초 사이의 타임아웃 제한이 있습니다. 복잡한 코드 파일을 분석할 때는 이 제한 시간을 초과하는 경우가 빈번했고, 이로 인해 사용자 경험이 크게 저하되었습니다.
Express 서버를 별도로 배포함으로써
초기에는 Next.js의 API 라우트 기능을 사용하여 프론트엔드와 백엔드 로직을 하나의 코드베이스에서 관리했습니다. 하지만 프로젝트가 성장하면서 두 영역의 책임이 점점 더 명확히 구분되어야 했습니다.
초기에는 프론트엔드에서 Firebase SDK를 사용하여 데이터베이스에 직접 접근했습니다. 이 방식은 편리하지만 몇 가지 문제를 가지고 있었습니다
서버를 분리함으로써 각 부분을 독립적으로 확장할 수 있게 되었습니다
프로젝트에서 중요한 부분인 코드 분석 기능은 OpenAI API를 사용합니다. API 키를 안전하게 관리하기 위해 이 호출은 서버 측에서 이루어져야 했습니다.
클라이언트 SDK에서 Admin SDK로 전환하면서 얻은 이점:
Express 서버에 다음과 같은 주요 API 엔드포인트를 구현했습니다:
Express 서버에서는 OpenAI API 호출에 대한 타임아웃을 더 효과적으로 제어할 수 있었습니다:
// 타임아웃 설정
const timeoutPromise = new Promise(
(_, reject) => setTimeout(() => reject(new Error("분석 시간 초과")), 60000) // 60초 타임아웃
);
// 분석 요청과 타임아웃 경쟁
const analysis = await Promise.race([
analyzeCode(apiKey, fileName, fileContent),
timeoutPromise,
]);
또한 적절한 오류 처리와 사용자 피드백을 추가하여 장시간 실행되는 작업에 대한 사용자 경험을 크게 개선했습니다.
프론트엔드 코드를 수정하여 Firebase 직접 접근 대신 서버 API를 호출하도록 변경했습니다:
// 변경 전: Firebase SDK 직접 사용
const docRef = await addDoc(collection(db, NOTES_COLLECTION), {
...note,
createdAt: serverTimestamp(),
updatedAt: serverTimestamp(),
});
// 변경 후: 서버 API 호출
const response = await fetch(`${API_URL}/api/note`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(note),
});
이 마이그레이션을 통해 얻은 주요 이점과 학습 포인트
Next.js 애플리케이션에서 Express 서버를 분리하는 과정은 간단하지 않았지만, 이러한 아키텍처 변경은 프로젝트의 확장성, 보안, 유지보수성을 크게 향상시켰습니다. 특히 OpenAI와 같은 처리 시간이 긴 외부 API를 호출할 때 발생하는 타임아웃 문제를 해결함으로써 사용자 경험을 크게 개선할 수 있었습니다.
이 과정에서 "가장 간단한 것이 항상 최선은 아니다"라는 교훈을 얻었습니다. 초기 개발 속도를 위해 모든 것을 Next.js에 통합했지만, 장기적인 관점에서는 관심사를 명확히 분리하는 것이 더 나은 선택이었습니다.
서버리스 기능은 많은 장점을 제공하지만, 실행 시간 제한과 같은 제약을 이해하고 프로젝트 요구사항에 맞게 아키텍처를 설계하는 것이 중요합니다. 복잡하거나 시간이 많이 소요되는 작업의 경우, 전통적인 서버 구성이 여전히 더 나은 선택일 수 있는거 같습니다 !!