[Node.js / Express 5] REST API 설계와 프로젝트 세팅

1. API란 무엇인가

API(Application Programming Interface)는 애플리케이션을 프로그래밍할 때 복잡한 내부 구현을 숨기고 필요한 기능만 제공하는 도구다. console.log(), print()처럼 내부 동작을 몰라도 함수만 호출하면 된다.

어려운 것은 감추고 쉽게 상호작용할 수 있게 해주는 것이 인터페이스고, API는 그 개념을 애플리케이션 영역으로 가져온 것이다.

클라이언트-서버 통신에서의 API는 이 개념의 부분 집합이다. 서버가 어떻게 데이터를 처리하는지는 몰라도, 정해진 URL과 HTTP 메서드로 요청하면 약속된 응답이 돌아온다.

요청 흐름: 클라이언트(Browser/App) → HTTP 요청 → API Server(Express/Node.js) → 쿼리 → Database → 결과 → JSON 응답(200/400/500)

클라이언트는 API의 내부 구현을 알 필요 없이 약속된 요청만 보내면 된다.

2. REST API 설계 규칙

REST(Representational State Transfer)는 HTTP를 기반으로 한 웹 서비스 아키텍처 스타일이다. API Endpoint는 HTTP 메서드 + URL의 조합으로 정의된다.

URI 설계 규칙 6가지

  1. 동사 금지, 명사 사용 — /users/loginPOST /users
  2. 하이픈 사용, 언더스코어 금지 — /user-profile (O) / /user_profile (X)
  3. 복수 명사 사용 — /users, /stores, /reviews
  4. 단일 리소스는 ID로 — /users/{userId}
  5. 계층 관계는 URI에 표현 — /stores/{storeId}/reviews
  6. 소문자만 사용
Bad 예시 Good 예시 이유
/getUsers GET /users 동사 사용 금지
/user/delete/1 DELETE /users/1 HTTP 메서드로 행위 표현
/Users /users 소문자 사용
/user_list /users 하이픈 사용, 복수형
/users/1/posts/2/comments/3 /posts/2/comments 2단계 이하 권장

계층 관계 표현

  • /users/{userId}/posts — 특정 유저의 게시글
  • /posts/{postId}/comments — 특정 게시글의 댓글

2단계 이상 중첩은 /comments/{commentId}처럼 독립 리소스로 분리한다.

HTTP 메서드와 CRUD 매핑

메서드 CRUD 예시 설명
POST Create POST /users 새 리소스 생성
GET Read GET /users/{userId} 리소스 조회
PUT Update (전체) PUT /users/{userId} 리소스 전체 교체
PATCH Update (일부) PATCH /users/{userId}/nickname 리소스 일부 수정
DELETE Delete DELETE /users/{userId} 리소스 삭제

주요 HTTP 상태 코드

코드 이름 의미
200 OK 요청 성공
201 Created 리소스 생성 성공
204 No Content 성공했지만 반환할 데이터 없음 (DELETE 등)
400 Bad Request 잘못된 요청 (유효성 검사 실패 등)
401 Unauthorized 인증 필요 (로그인하지 않음)
403 Forbidden 인증은 됐지만 권한 없음
404 Not Found 리소스를 찾을 수 없음
409 Conflict 리소스 충돌 (이미 존재하는 이메일 등)
500 Internal Server Error 서버 내부 오류

3. Path Variable vs Query String

두 방식 모두 클라이언트가 서버에 추가 정보를 전달하는 수단이지만, 용도가 다르다.

구분 Path Variable Query String
형식 /users/42 /users?region=seoul&limit=20
용도 특정 리소스를 식별할 때 사용 필터링, 정렬, 페이지네이션에 사용
없을 경우 404 오류 발생 없어도 요청 성공
예시 특정 유저, 특정 게시글 검색 조건, 목록 필터

특정 1개를 집어야 한다면 Path Variable, 조건을 걸어 여러 개를 추릴 때는 Query String을 선택한다.

4. Request Body와 Request Header

HTTP 요청에는 URL 외에 Body와 Header를 통해 추가 데이터를 전달할 수 있다.

Request Body

POST / PUT / PATCH 요청에서 전송하는 데이터다. JSON 형식이 일반적이며, Content-Type: application/json 헤더와 함께 사용한다.

{
  "email": "user@example.com",
  "password": "secret123"
}

Request Header

요청의 메타데이터를 담는다. 주요 헤더는 다음과 같다.

헤더 역할
Content-Type: application/json Body 데이터의 형식을 지정한다
Authorization: Bearer {token} 인증 토큰을 서버에 전달한다

5. API 명세서 작성

API 명세서는 프론트엔드 개발자가 API를 사용하기 쉽도록 돕는 문서다. 백엔드와 프론트엔드가 협업하는 모든 프로젝트에서 필수적이다.

명세서 구성 요소

  1. Endpoint — HTTP 메서드 + URL
  2. Request — Body / Query String / Path Variable / Header
  3. Response — 성공 시 반환 데이터 구조 (JSON)
  4. Status Code — 200 OK / 201 Created / 400 Bad Request / 401 Unauthorized / 500 Internal Server Error
  5. Error Cases — 에러 코드와 메시지 목록

응답 형식 통일

팀 전체가 동일한 응답 구조를 사용하면 프론트엔드와의 협업이 쉬워진다.

{
  "resultType": "SUCCESS",
  "error": null,
  "success": {
    "id": 1,
    "email": "test@example.com",
    "name": "홍길동"
  }
}

실패 응답은 다음과 같은 구조를 사용한다.

{
  "resultType": "FAILURE",
  "error": {
    "errorCode": "U001",
    "reason": "이미 존재하는 이메일이다.",
    "data": null
  },
  "success": null
}

회원가입 API 명세 예시

항목 내용
Endpoint POST /api/v1/users/signup
Content-Type application/json
Request Body email: string
password: string
name: string
Response 200 { "result": "success", "data": { "userId": 1 } }
Error Cases E4001: 이미 가입된 이메일
E4002: 비밀번호 형식 오류
E5000: 서버 오류

API 버전 관리

/api/v1/...처럼 URL에 버전을 포함하면 v2를 출시할 때 기존 클라이언트가 v1을 계속 사용할 수 있어 하위 호환성을 유지할 수 있다.

6. Express 5 프로젝트 세팅

Node.js 22 LTS 설치 후 다음 순서로 프로젝트를 초기화한다.

패키지 설치

npm init -y
npm install express@^5.0.0
npm install --save-dev nodemon

Nodemon은 파일 변경을 감지하면 서버를 자동으로 재시작하는 도구이다. --watch src 옵션으로 특정 폴더만 감시할 수 있다.

{
  "scripts": {
    "dev": "nodemon --watch src src/index.js",
    "start": "node src/index.js"
  }
}

package.json 설정

package.json에 "type": "module"을 추가하면 .js 파일에서 import/export 문법을 사용할 수 있다. 이 설정 없이는 CommonJS 방식(require)을 사용해야 한다.

{
  "type": "module",
  "scripts": {
    "dev": "nodemon --watch src src/index.js",
    "start": "node src/index.js"
  }
}
import express from 'express';
import dotenv from 'dotenv';

dotenv.config();
const app = express();

src/index.js

import express from 'express'

const app = express()
const PORT = process.env.PORT ?? 3000

app.use(express.json())

app.get('/', (req, res) => {
  res.send('Hello World')
})

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

Express 5는 async 핸들러에서 발생한 오류를 자동으로 next(err)로 전달한다. try/catch 없이도 에러 미들웨어가 작동한다는 것이 Express 4와의 가장 큰 차이다.

핵심 키워드

REST (Representational State Transfer)

HTTP를 기반으로 한 웹 서비스 아키텍처 스타일이다. 자원(Resource), 행위(Verb), 표현(Representation)의 세 가지 요소로 구성된다.

API Endpoint

HTTP 메서드 + URL 조합으로 하나의 기능을 가리키는 주소다. POST /usersGET /users는 URL이 같아도 서로 다른 Endpoint다.

Path Variable

URI 경로에 포함된 동적 값이다 (/users/{userId}). 특정 리소스를 식별하는 데 사용하며, 값이 없으면 404를 반환한다.

Query String

URL 뒤에 ?key=value 형태로 붙는 선택적 파라미터다. 필터링, 정렬, 페이지네이션에 사용하며 없어도 요청은 성공한다.

Request Body

POST / PUT / PATCH 요청 시 함께 보내는 데이터다. JSON 형식이 일반적이며 Content-Type: application/json 헤더와 함께 전송한다.

API 명세서

Endpoint, 요청/응답 구조, 상태 코드, 오류 케이스를 문서화한 것이다. 프론트엔드와 백엔드가 동시에 개발할 수 있도록 인터페이스를 미리 합의하는 역할을 한다.