Develop

Express.js REST API 완벽 가이드 — Node.js 백엔드 서버 구축하는 방법

Node.js 기반 백엔드 아키텍처의 오랜 정석인 Express.js 프레임워크를 사용해 모듈화된 REST API 서버를 안전하게 조립하고, 매개변수 개수가 특이한 전역 에러 핸들러 셋업 및 미들웨어 충돌 방지 팁을 기술했습니다.

Express.jsREST APINode.js백엔드backend
Postman에서 Express.js REST API 엔드포인트를 테스트하는 화면 — Node.js 백엔드 서버 응답 예시
  • ·Express.js는 Node.js 웹 프레임워크 중 가장 오래되고 광범위하게 쓰이며 npm 주간 다운로드 수 천만 건을 기록한다
  • ·Express 미들웨어는 요청-응답 사이클에서 순서대로 실행되며 next()를 호출해야 다음 미들웨어로 넘어간다
  • ·에러 처리 미들웨어는 파라미터가 4개(err, req, res, next)여야 Express가 에러 핸들러로 인식한다
  • ·express.json() 미들웨어를 등록하지 않으면 req.body가 undefined로 처리된다
Express.js로 복잡한 데이터베이스 트랜잭션을 수반하는 백엔드 서버를 손수 구축해 나가는 도중, 컨트롤러에서 발생시킨 런타임 예외 에러가 중앙 전역 에러 제어 장치로 모이지 않고 서버 프로세스를 다운시켜 버리는 버그 때문에 반나절을 씨름했습니다. 당연히 일반 미들웨어처럼 파라미터를 3개(`req, res, next`)만 기재해서 짰던 탓이었습니다. 에러 처리기 핸들러는 **반드시 4개의 인자(`err, req, res, next`)를 통째로 선언해 두어야만** 익스프레스가 비로소 전역 에러 핸들러로 인식해 낚아챈다는 문법 제약을 뼈저리게 배운 후, 미들웨어 배치 선언 순서의 민감성 트레이드오프와 함께 안전한 아키텍처 빌드 프로세스를 몸소 장착했습니다.

1. 모듈러 설계와 라우팅 구조

테스트와 확장이 용이한 Express.js 백엔드 REST API 설계 뼈대 구축

Express.js는 정형화된 폴더 구조 구조물이 없으므로 개발자가 아키텍처 뼈대를 지혜롭게 설계해야 덩치가 커졌을 때 파편화되지 않습니다. 진입점 파일인 app.ts 에는 순수 미들웨어 세팅과 외부 라우터 연결만 선언해 두고, 실제 포트 개방 명령(app.listen)은 별개 파일인 server.ts 로 분리 기재하는 설계 아키텍처가 훌륭한 실무 패턴입니다. 이렇게 셋업해 두어야만, 유닛 테스트를 기동할 때 가상의 포트 개방 충돌 없이 익스프레스 인스턴스(app)만 쏙 뽑아내어 테스트 라이브러리(supertest 등)로 고속 모의 요청 검증을 매끄럽게 가동할 수 있습니다.

2. 파이프라인과 미들웨어 작동

호출 순서에 주의해야 하는 Express.js 미들웨어 체인 구성법

Express의 본질은 요청이 도달해 응답으로 나가기까지의 미들웨어 함수 체인 연결망입니다. app.use 로 선언해 붙여준 순서 그대로 요청 신호가 흘러가죠. 미들웨어 함수를 직접 짤 때는 마지막 마감부에 next() 명령어를 쳐주어야 다음 바통으로 신호가 넘어갑니다. 한 가지 왕초보들이 자주 범하는 에러는 바디 파서 미들웨어인 express.json() 선언부를 개별 API 라우터 등록문보다 뒤편에 배치해 버리는 실수입니다. 순서가 꼬이면 라우터 컨트롤러가 req.body 속성을 해독하지 못하고 undefined 널 값을 반품해 뻗어 버리니, 무조건 파서 셋업을 소스 코드 최상단에 박아 두어야 든든합니다.

파라미터 개수 제약이 있는 Express.js 전역 에러 처리 미들웨어 설정

비즈니스 로직 내부에서 뿜어져 나오는 모든 DB 에러와 예외 신호를 수거하는 전역 에러 핸들러는 미들웨어 체인의 가장 맨 마지막 바닥 자리에 할당되어야 합니다. 또한 선언할 때 일반 미들웨어 매개변수 형식과 달리 **err 변수를 포함해 총 4개의 파라미터((err, req, res, next) => {})를 반드시 풀 세트로 적어주어야만** 익스프레스 커널 엔진이 '아, 이것은 에러를 수거해 가는 특별한 빗자루 미들웨어구나' 라고 감지해 제어권을 안전하게 토스해 줍니다. 괄호 속 인자가 3개 이하로 누락되면 빗자루 장치가 작동을 멈추고 생 에러를 화면에 뿌려버리니 괄호 속 개수를 항상 감시하셔야 합니다.

import express from 'express';
import cors from 'cors';
import { usersRouter } from './routes/users';

const app = express();

// 1. 공통 바디 파서 및 보안 린터 최상단 배치
app.use(cors());
app.use(express.json());

// 2. 개별 API 라우터 연동
app.use('/api/users', usersRouter);

// 3. 전역 예외 처리 미들웨어 (반드시 매개변수 4개 고수 및 맨 마지막 배치)
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
  const status = err.statusCode || 500;
  const message = err.message || '서버 내부 시스템 오류';
  
  console.error('[전역 에러 감지]:', err.stack);
  res.status(status).json({ success: false, error: message });
});

3. 환경변수 격리와 서버 실행

Dotenv 환경 설정과 Express.js 백엔드 서비스 배포 아키텍처

데이터베이스 계정 암호나 외부 결제 시크릿 키가 소스 파일 하드코딩으로 인해 깃허브 공개 리포지토리에 푸시되는 보안 참사를 차단하기 위해 dotenv 모듈을 연동해 가둡니다. 빌드 진입점 최상단에 import 'dotenv/config' 한 줄을 명시하여 로컬 디렉토리의 .env 파일 정보가 메모리에 주입되게 구성하죠. 실 운영 환경에 이미지를 배포할 때는 소스 코드를 자바스크립트로 빌드 컴파일(tsc)하여 나온 dist/server.js 파일을 기동 타겟으로 설정하고, 무중단 프로세스 매니저인 PM2 헬퍼를 태워 클러스터 모드로 구동해 둠으로써 하드웨어 코어 자원을 100% 한계치까지 활용하는 탄탄한 백엔드 운용망을 마감 구축합니다.

자주 묻는 질문

비동기 async/await 컨트롤러 안에서 터진 DB 에러가 전역 에러 핸들러로 전달되지 않고 프로세스가 다운됩니다.+

Express 4 버전은 비동기 async 함수 내부에서 던져진 예외를 스스로 캐치해 next로 넘기지 못합니다. 비동기 쿼리 영역 전체를 `try-catch`로 둥글게 감싸 catch 단에서 `next(err)`를 명시적으로 실행해 주거나, 컨트롤러 함수 전체를 감싸서 자동으로 next를 실행해 주는 `express-async-handler` 같은 헬퍼 데코레이터를 바인딩해 활용하셔야 예외가 전역 에러 미들웨어로 수거됩니다.

express.json() 과 express.urlencoded() 두 가지 바디 파서의 실제 차이가 무엇인가요?+

`express.json()` 은 HTTP body 내용이 순수 JSON 포맷 문자열로 유입되었을 때 객체로 해석해 주는 장치이고, `express.urlencoded()` 는 HTML `<form>` 태그의 폼 전송 방식(쿼리스트링처럼 인코딩된 포맷)으로 유입되는 데이터를 파싱해 줍니다. 폼 전송까지 수용하는 전통적인 REST API 서버라면 두 가지를 나란히 나열 선언해 두는 것이 안전합니다.

관련 글