3월에 팀프로젝트를 시작하는데, 처음으로 백엔드로 참여를 해볼 생각이다.
그런데 기본적인 강의를 제외하고는 준비하고 있는게 없어서, 실질적으로 프로젝트에 도움이 될만한 것을 개인적으로 더 공부해야겠다는 생각이 들었다.
백엔드 하면 API 명세가 가장 중요하고, 모든 프로젝트의 시작이라는 생각에 예전에 프로젝트에서 백엔드 분들이 보여주셨던 Swagger를 공부해보면 갈피가 잡힐 것같아 정리해보았다. 이를 바탕으로 개발스터디 발표도 진행하였다.

✨ Swagger
: REST API를 설계, 빌드, 문서화, 소비하기 위한 오픈 소스 소프트웨어 프레임워크
OAS (OpenAPI Specification)
: RESTful API가 어떻게 동작하는지 설명하는 표준 명세서 - YAML, JSON 파일로 작성
→ 💡 이를 시각화해주거나, 코드를 생성해주는 구현체 도구들의 모음이 Swagger!
🤔 왜 사용하는거지?
- api 명세를 별도의 설치 없이 직관적인 UI로 확인할 수 있다.
- Controller에 몇가지 어노테이션을 달기만 해도 API 문서가 만들어진다.
- 실제로 서버에 test packet을 보내서 응답을 확인해볼 수 있다
| Swagger | Postman | |
| 목적 | 문서화 | 요청/테스트 |
| 사용 시점 | 설계 단계 + 문서 공유 | 개발/디버깅 |
| 협업 | API 계약서 역할 | 개인/팀 테스트 |
| 자동 문서화 | O | X |
| 실제 호출 테스트 | 가능 | 더 강력 |
| - 코드 기반 - Git에 포함 - 서버와 함께 버전관리됨 - 자동 문서 생성 |
- 앱 기반 - 컬렉션 export로 Git에 올릴 수 있음 - 팀 Workspace 협업 가능 - 코드와 묶여있지 않음 |
하나의 프로젝트 파일 안에서 코드 형태로 작성하고, URL로 바로 접속이 가능한다는 점에서 Postman보다 압도적으로 협업에 편리하겠다는 생각이 들었다.
실습
Swagger를 이용하는 방식 두가지
1️⃣ 특정 서버 플랫폼에 종속적으로 사용하는 방식
- Express 코드 위에 @swagger 주석으로 명세를 작성하는 방식
- 동기화가 쉬움
- 서버 언어에 따라 달라짐
- 코드와 문서가 한 파일에 있음. → 길어지면 파일이 무거워짐!!
const express = require('express');
const router = express.Router();
const conn = require('../mariadb');
const {
join,
login,
passwordResetRequest,
passwordReset
} = require('../controller/UserController');
router.use(express.json());
/**
* @swagger
* /users/join:
* post:
* summary: 회원가입
* tags: [Users]
* description: 새로운 사용자를 등록합니다.
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - email
* - password
* properties:
* email:
* type: string
* description: 사용자 이메일
* example: test@gmail.com
* password:
* type: string
* description: 사용자 비밀번호
* example: password123
* responses:
* 201:
* description: 회원가입 성공
* 400:
* description: 잘못된 요청
*/
router.post('/join', join); // 회원가입
/**
* @swagger
* /users/login:
* post:
* summary: 로그인
* tags: [Users]
* description: 이메일과 비밀번호로 로그인합니다.
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* password:
* type: string
* responses:
* 200:
* description: 로그인 성공
* 401:
* description: 인증 실패
*/
router.post('/login', login); // 로그인
// ... 나머지 라우트들 ...
router.post('/reset', passwordResetRequest);
router.put('/reset', passwordReset);
module.exports = router;
✔️ 2️⃣ 서버 프로그래밍 언어를 전혀 거치지 않고, swagger api 문서(yml)을 완전히 독립적으로 빼내서 사용하는 방식 ✔️
- 서버 코드와 문서 완전 분리
- 서버 언어에 독립적
- 문서 중심 설계 가능(API 명세 → 서버 개발)
- 대규모 협업에 유리 - 백엔드/프론트/기획이 문서로 협의 가능
- 문서와 코드 불일치 가능성
보통 당연시하게 2️⃣ 번의 방법을 사용하는 것같았다.
파일 하나에 router별로 @swagger주석을 다는 건 실질적으로,, 상식적으로 생각해도 정말 비효율적이고 가독성이 떨어지는 느낌이 있다.
그리고 무엇보다 파일을 따로 나누면 프론트엔드 측에서도 편하게 확인하고 수정할 수 있는 부분에서 훨씬 효율적인 것같아 2번의 방법으로 공부를 해나가는 것을 선택했다.
1️⃣ 필수 라이브러리 설치
npm install swagger-ui-express yamljs swagger-cli
swagger-ui-express: 작성해준 API 명세를 UI로 보여줌yamljs: YAML파일을 읽어서 Node.js가 이해할 수 있는 객체(JSON)으로 변환해줌swagger-cli: 나눠져있는 yaml 파일을 하나의swagger.yaml파일로 합쳐주는 역할- 참고 npm 링크https://www.npmjs.com/package/swagger-ui-express
- https://www.npmjs.com/package/swagger-cli
- https://www.npmjs.com/package/swagger-jsdoc
2️⃣ app.js에 Swagger 연결
const swaggerUi = require('swagger-ui-express');
const yaml = require('yamljs');
//아까 install했던 것들
const path = require('path');
//node.js 기본 내장 모듈, 파일 경로 찾을 때 에러 방지하고 현재 폴더 위치 정확하게 찍어줌 (윈도우 \, 맥리눅스 / 기호 다른 것 통일해줌)
const swaggerSpec = yaml.load(path.join(__dirname, './swagger.yaml'));
// __dirname : 현재 이 파일이 있는 현재 폴더 위치
// path.join(...) : 현재 위치와 ./swagger.yaml 파일 이름 합쳐서 정확한 절대경로 만들어줌
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
//api-docs로 서버를 들어오면 이것을 보여줘!
//swaggerUi.serve : UI 그리기 위한 핵심 파일들 준비
//swaggerUi.setup(swaggerSpec)) : 준비된 화면에 아까 읽어온 내용(swaggerSpec) 읽어와서 펼쳐주는 함수
3️⃣ Swagger 폴더 구조 만들기
book-shop
├─ app.js
├─ swagger/
│ ├─ index.yaml
│ ├─ paths/
│ │ └─ users.yaml
│ └─ components/
│ └─ schemas.yaml

4️⃣ components/schemas.yaml 작성 - 데이터 구조 정의
components:
schemas:
User:
type: object
required:
- email
- password
properties:
email:
type: string
example: "test@gmail.com"
description: "사용자 이메일"
password:
type: string
example: "password123"
description: "사용자 비밀번호"
EmailOnly:
type: object
required:
- email
properties:
email:
type: string
example: "test@gmail.com"
description : "비밀번호 초기화 요청"
TokenResponse:
type: object
properties:
email:
type: string
example: "test@gmail.com"
description : "로그인 성공 응답 구조"
5️⃣ paths/users.yaml 작성 - API 명세 정의
paths:
/users/join:
post:
summary: "회원가입"
description: "새로운 사용자를 등록합니다."
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/User'
responses:
201:
description: "회원가입 성공"
400:
description: "잘못된 요청"
/users/login:
post:
summary: "로그인"
description: "이메일과 비밀번호로 로그인합니다."
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/User'
responses:
200:
description: "로그인 성공 (쿠키에 JWT 저장)"
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/TokenResponse'
401:
description: "로그인 실패"
400:
description: "잘못된 요청"
/users/reset:
post:
summary: "비밀번호 초기화 요청"
description: "이메일이 존재하는지 확인합니다."
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/EmailOnly'
responses:
200:
description: "이메일 존재 확인"
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/EmailOnly'
401:
description: "이메일 없음"
400:
description: "잘못된 요청"
put:
summary: "비밀번호 재설정"
description: "새 비밀번호로 변경합니다."
tags:
- Users
requestBody:
required: true
content:
application/json:
schema:
$ref: '../components/schemas.yaml#/components/schemas/User'
responses:
200:
description: "비밀번호 변경 성공"
400:
description: "변경 실패"
6️⃣ index.yaml 작성 - 전체 문서의 시작점
openapi: 3.0.0
info:
title: Book Shop API
version: 1.0.0
description: "Book Shop 프로젝트 API 명세서입니다."
paths:
$ref: './paths/users.yaml#/paths'
components:
schemas:
$ref: './components/schemas.yaml#/components'
7️⃣ 여러 파일을 하나로 합치기 - 번들화
지금 구조로는 $ref 로 파일을 나눠놨기 때문에 Swagger UI에서 안정적으로 읽으려면 하나의 파일로 합쳐야 합니다.
package.json에 추가
"scripts": {
"start": "node app.js",
"api-docs": "swagger-cli bundle ./swagger/index.yaml --outfile ./swagger.yaml --type yaml",
"prestart": "npm run api-docs"
}
여러 파일로 나뉜 OpenAPI 문서를 하나의 완성된 swagger.yaml 파일로 자동으로 합쳐줌
8️⃣ 서버 실행
npm start
http://localhost:9999/api-docs 으로 Swagger UI 화면 접속

- 참고 링크
- https://velog.io/@myqewr/spring-API-문서-자동화-Spring-rest-docs-Open-API-SpecificationOAS
- https://velog.io/@kyy00n/Node.js-Swagger-개요-적용
- https://velog.io/@hyex/Node.js-TS-프로젝트에-swagger-적용하기-Feat.-파일-분리
[spring] API 문서 자동화 : Spring rest docs + Open API Specification(OAS)
api를 문서화하는 방법은 매우 다양하다. 지금하고 있는 프로젝트의 api 명세 방법으로는 postman을 사용해 왔다. 그런데 쓰면서도 굉장히 불편함을 느꼈다. api를 등록하기 위해 일일히 url을 다 작
velog.io
'BE > Node.js' 카테고리의 다른 글
| 랜덤 데이터 생성 API(mockaroo, Fakerjs) (0) | 2026.03.24 |
|---|---|
| [Node.js] express-generator로 Express 구조 해부해보기 (0) | 2026.01.23 |