개념
Swagger, OpenAPI, Swagger UI — 셋을 먼저 갈라놓자
실무 대화에서 "스웨거 봤어요?"라는 한 문장이 서로 다른 세 가지를 가리킨다. 여기서 헷갈리면 이후 모든 설명이 흐려지므로 먼저 정리한다.
| 말 | 실체 | QA가 만나는 모습 |
|---|---|---|
| OpenAPI | API를 기술하는 표준 규격 (YAML/JSON 문서) | /v3/api-docs, openapi.json 같은 주소의 긴 JSON |
| Swagger UI | 그 규격 문서를 사람이 읽고 실행할 수 있는 화면 으로 그려주는 도구 | /swagger-ui.html, /docs 같은 주소의 웹 페이지 |
| Swagger (넓은 뜻) | 위 규격과 도구 모음을 만든 회사·제품군의 이름 | 팀에서는 보통 "Swagger UI 화면"을 뜻한다 |
원래 규격 이름이 Swagger였다가 2015년 표준화되면서 OpenAPI 로 이름이 바뀌었다. 그래서 "Swagger 스펙"과 "OpenAPI 스펙"은 사실상 같은 말이고, 모듈 12(레슨 4)에서 계약 테스트의 근거로 쓴 그 스펙 파일이 바로 Swagger UI 화면이 읽어들이는 원본이다.
핵심은 이것이다. Swagger UI는 스펙을 그려줄 뿐, 스스로 문서를 쓰지 않는다. 화면에 보이는 모든 설명·필드·예시는 서버 코드에서 생성된 스펙에서 나온다. 그래서 코드가 바뀌면 화면도 따라 바뀌고, 반대로 코드에 주석이 부실하면 화면도 똑같이 부실하다.
화면은 세 덩어리로 읽는다
처음 Swagger UI를 열면 알록달록한 줄이 수십 개 쏟아져 당황하기 쉽지만, 구조는 단순하다.
┌─────────────────────────────────────────────┐
│ API 제목 · 버전 · 서버 주소 선택 [Authorize]│ ← ① 머리말
├─────────────────────────────────────────────┤
│ ▼ order (태그 = 기능 묶음) │
│ GET /orders/{id} 주문 단건 조회 🔓 │ ← ② 엔드포인트 목록
│ POST /orders 주문 생성 🔒 │
│ DELETE /orders/{id} 주문 취소 🔒 │
├─────────────────────────────────────────────┤
│ ▼ Schemas │
│ Order { id, status, totalPrice, ... } │ ← ③ 데이터 모양 사전
└─────────────────────────────────────────────┘① 머리말 — API 이름과 버전, 그리고 요청이 실제로 날아갈 서버
주소 가 있다. 드롭다운으로 개발·스테이징을 고를 수 있는 경우가
많은데, 여기를 확인하지 않고 테스트하다 운영 서버에 주문을
생성해버리는 사고가 실제로 난다. Authorize 버튼도 여기 있다.
② 엔드포인트 목록 — 색깔이 곧 HTTP 메서드다(GET 파랑, POST
초록, PUT 주황, DELETE 빨강). 태그(order, user 등)로 묶여 있고,
줄 오른쪽 자물쇠 아이콘은 "이 API는 인증이 필요하다" 는 표시다.
③ Schemas — 응답·요청에 쓰이는 데이터 구조 사전이다. 어떤 필드가
필수(* 표시)이고 타입이 무엇인지, enum으로 값이 제한돼 있는지가
여기 다 있다. 테스트 설계의 재료가 가장 많이 나오는 곳 이다.
실행 흐름 6단계
한 엔드포인트 줄을 클릭해 펼친 뒤 순서대로 간다.
- 접속 — 개발자가 알려준 Swagger UI 주소를 브라우저로 연다.
- API 선택 — 테스트할 줄을 눌러 펼친다. Parameters(입력)와 Responses(응답 예시)가 보인다.
- Try it out — 오른쪽 위 버튼을 누른다. 이때부터 입력칸이 읽기 전용에서 편집 가능 으로 바뀐다.
- 값 입력 — 경로 변수(
{id}), 쿼리 파라미터, 요청 본문(JSON)을 채운다. 본문은 예시가 미리 채워져 있으니 필요한 값만 고치면 된다. - Execute — 누르는 순간 브라우저가 진짜 서버로 요청을 보낸다. 시뮬레이션이 아니라 실제 호출 이다.
- 결과 확인 — 응답 코드·본문·헤더, 그리고 그 위의
curl명령과 Request URL이 함께 나온다.
Execute 아래 나오는 curl과 Request URL이 진짜 쓸모 있다
많은 사람이 응답 본문만 보고 지나치는데, QA에게는 그 위 두 줄이 더 값지다.
curl -X 'POST' \
'https://api-dev.example.com/v1/orders' \
-H 'accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOi...' \
-H 'Content-Type: application/json' \
-d '{"itemId": 1001, "quantity": 2}'이 한 덩어리가 재현 절차 그 자체 다. 결함 리포트에 붙여 넣으면
개발자가 똑같은 요청을 그대로 재현할 수 있다 — 모듈 6에서 배운
"재현 가능한 결함 리포트"를 API 레벨에서 가장 싸게 만드는 방법이다.
다만 토큰이 그대로 박혀 있으므로, 붙여 넣기 전에 Bearer ... 값은
<TOKEN> 으로 지우는 습관을 들인다.
인증(토큰) 설정 — Authorize 버튼의 정체
자물쇠가 달린 API를 그냥 Execute 하면 401 Unauthorized가 돌아온다.
로그인한 사용자로 실행하려면 오른쪽 위 Authorize 버튼 을 눌러
자격 증명을 한 번 등록해야 한다. 등록하면 이후 모든 요청에 자동으로
붙는다.
어떤 입력창이 뜨는지는 스펙의 securitySchemes가 결정한다. 실무에서
만나는 건 대개 이 셋이다.
components:
securitySchemes:
bearerAuth: # ① 가장 흔함 — JWT 토큰
type: http
scheme: bearer
bearerFormat: JWT
apiKeyAuth: # ② 헤더에 키를 그대로 싣는 방식
type: apiKey
in: header
name: X-API-KEY
oauth2Auth: # ③ 인가 서버를 거쳐 토큰을 받아오는 방식
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read:orders: 주문 조회① bearer 방식에서 가장 많이 나는 실수 하나만 기억하자.
type: http, scheme: bearer 로 정의된 경우 Swagger UI가 Bearer
접두어를 자동으로 붙인다. 그런데 습관적으로 Bearer eyJhb... 을
통째로 붙여 넣으면 실제 헤더가 이렇게 나간다.
Authorization: Bearer Bearer eyJhbGciOi... ← 401. 입력창에는 토큰만 넣는다반면 ② apiKey 방식은 입력한 문자열이 그대로 헤더에 실린다. 즉 접두어가 필요하면 직접 넣어야 한다. "붙여 넣는 값이 같아도 방식에 따라 결과가 다르다"는 점이 초심자가 가장 오래 헤매는 지점이다.
③ OAuth2 는 입력창 대신 팝업으로 인가 서버 로그인 화면이 뜨고,
돌아오면 토큰이 자동으로 채워진다. 이때 화면에 보이는 스코프
체크박스가 곧 권한 테스트의 재료 다 — read:orders만 체크하고
주문 생성을 호출해 403이 나오는지 보는 식으로 권한 경계를 확인할
수 있다.
토큰은 어디서 구하나
QA가 가장 자주 막히는 현실적인 문제다. 경로는 셋 중 하나다.
- 같은 Swagger 안의 로그인 API를 먼저 실행 한다.
POST /auth/login에 테스트 계정을 넣고 Execute → 응답 본문의accessToken값을 복사 →Authorize에 붙여 넣는다. 가장 깔끔한 방법이고, 이 자체가 "로그인 API 테스트"를 겸한다. - 개발자에게 발급받는다. 이때 유효기간과 권한(역할) 을 반드시 같이 묻는다. "관리자 토큰인지 일반 사용자 토큰인지"를 모르고 테스트하면 권한 결함을 통째로 놓친다.
- 웹 화면에 로그인한 뒤 개발자도구 Network 탭에서 요청 헤더의
Authorization값을 복사한다(모듈 19 레슨 4의 프록시·모듈 9의 DevTools 기법과 같은 자리).
토큰에는 만료 시간 이 있다. 30분쯤 뒤 갑자기 모든 요청이 401로 바뀌면 십중팔구 서버가 죽은 게 아니라 토큰이 만료된 것이다. 브라우저를 새로고침하면 Authorize 등록도 함께 풀린다는 점도 같이 기억한다.
응답에서 QA가 실제로 봐야 할 네 가지
Execute 후 "200 나왔네, 통과"로 끝내면 도구를 절반만 쓴 것이다.
- 상태 코드 — 성공 경로뿐 아니라 잘못된 입력에 대해 400인지 500인지가 중요하다. 잘못 보냈는데 500이 오면 그 자체가 결함 이다 (서버가 방어하지 못하고 터졌다는 뜻).
- 본문의 실제 값 — 스펙의 예시가 아니라 돌아온 값이다.
number로 선언된totalPrice에"9000"문자열이 오는 식의 계약 위반은 모듈 12(레슨 4)에서 본 그대로다. - 헤더 —
Content-Type, 캐시 헤더, 그리고 페이지네이션 정보가 헤더에 실리는 API도 많다. - Response duration — Swagger UI는 응답 시간을 함께 보여준다. 조회 한 건이 3초라면 그것만으로 성능 이슈 제보 근거가 된다.
실무에서 왜 필요한가
QA가 API를 직접 두드릴 수 있으면 결함의 위치를 한 단계 좁혀서
말할 수 있다. 화면에 주문 금액이 잘못 나올 때 "화면이 이상합니다"가
아니라 "GET /orders/1001 응답의 totalPrice가 이미 9000으로
옵니다 — 서버 쪽입니다"까지 말하는 것과는 대응 속도가 다르다.
그리고 Swagger UI는 설치가 필요 없다. 신입이 입사 첫 주에, 혹은 외부 협력사 QA가 계정만 받은 상태에서 즉시 API 테스트를 시작할 수 있는 유일한 경로인 경우가 많다. 프런트엔드 화면이 아직 없는 기능도 API만 완성됐다면 Swagger로 먼저 검증해 테스트를 왼쪽으로 당길 수 있다 — 모듈 11에서 배운 시프트 레프트의 가장 값싼 실천이다.
마지막으로, Swagger UI 화면은 개발자와 QA가 같은 것을 보고 말하게
만든다. "이 API에 status 필드 있나요?"라는 질문이 오가는 대신
같은 URL을 함께 보면서 "여기 enum에 CANCELED가 없는데 취소 상태는
뭘로 오나요?" 같은 구체적 질문으로 바뀐다.