📂 목차
📚 본문
Swagger
소프트웨어 간에 상호작용을 하기 위해 제공하는게 바로 API 문서다. API 수가 많아지만 이런 문서 작성도 굉장히 버겁게 된다. 이런 문서를 자동화 할 수 있는 것이 바로 Swagger 이다.
API 문서화
개발자가 API 를 이해하고 사용할 수 있도록 구조, 요청 / 응답 방식, 인증, 오류 등을 정리한 문서이며 문서가 없거나 불완전하면 코드 분석, 문의 등 비효율이 발생하게 된다. 명확한 문서는 개발자 경험과 유지보수 효율을 높일 것이다.
주요 요소
- end point: URL, HTTP 메서드(GET/POST/PUT/DELETE)
- reuqest: 필요 파라미터, 헤더
- response: 응답 데이터 구조, HTTP status code
- Examples 요청/응답: 실제 호출 예시, 예상 결과
- Error Code 설명: 발생 가능한 오류 코드 및 해결 방법
Swagger 및 OpenAPI 개념 정리
Swagger 는 API 문서를 자동 생성/관리하는 도구이며 OpenAPI Specification 표준 기반으로 API 명세를 정의하고, 작성된 명세를 활용하여 문서, 테스트 UI, 코드 생성 등을 자동화할 수 있게 된다.
OpenAPI Specification(OAS)
- RESTful API 를 기술하는 표준 포맷
- YAML/JSON 형식으로 API 구조 정의
- 대부분의 언어/프레임워크에서 활용 가능
- Swagger UI, Redoc 등을 통해 문서 자동 생성 가능
Swagger 구성 요소
- Swagger UI
- 브라우저 API 문서의 시각적 제공
- API를 직접 테스트할 수 있는 인터랙티브 UI
- Swagger Editor
- API 명세(YAML/JSON)를 작성하는 온라인 편집기
- 실시간 미리보기
- Swagger Codegen
- API 명세를 기반하여 클라이언트 SDK, 서버 스텁 코드 자동 생성
Swagger 장점
주요기능으로는 다음과 같다:
자동화된 API 문서 생성 Swagger 는 어플리케이션 코드에 작성한 애노테이션을 기반으로 API 문서를 자동으로 생성하는데, 별도의 작업 없이도 엔드포인트, 파라미터, 응답 구조 등이 자동으로 반영되기 때문에 문서를 직접 작성하던 시대와 비교하면 압도적으로 효율적이다.
인터랙티브 API 테스트 기능 제공
Swagger UI는 단순 문서가 아니라 브라우저에게 바로 API 를 호출해볼 수 있는 살아있는 테스트 환경을 제공하기 때문에 개발/QA/기획자가 Postman, curl 기능 없이 바로 API 를 검증할 수 있다는 큰 장점이 있다.
언어 및 프레임워크 독립적 구조 Swagger/OAS는 특정 언어나 프레임워크에 종속되지 않는다. Java(Spring), Node.js, Python(FastAPI), Golang 등 어떤 환경에서도 동일한 방식으로 문서를 작성하고 공유할 수 있어 팀 간 표준화가 수월하다.
표준화된 API 명세(JSON/YAML) 제공 API 구조를 JSON 또는 YAML 로 표현하는 Open API Specification(OAS) 를 그대로 따르게 된다. 이를 통해 도구 간 호환성이 높고, 외부 시스템과의 연동이나 API 관리 플랫폼에서도 바로 사용할 수 있다.
Swagger Dependency
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5'Swagger application.yml 설정
api-docs 기능 설정
springdoc:
api-docs:
path: /api-docs
enabled: truespringdoc 은 swagger 에서 전용으로 사용하는 key block 이다. api-docs 는 API 명세를 JSON 형태로 보여준다. /api-docs 로 설정했으므로 scheme 뒤에 path 자리에 /api-docs 를 써준다면 JSON 형태로 볼 수 있다.

swagger-ui 기능 설정
swagger-ui:
path: /swagger-ui.html
enabled: true
operations-sorter: method
tags-sorter: alpha
display-request-duration: true
default-consumes-media-type: application/json
default-produces-media-type: application/jsonswagger-ui 는 JSON 형태 외의 html 형태로 유저에게 시각적으로 보여준다. 웹사이트가 기본적으로 꾸며져 있기 때문에 따로 우리가 디자인하지 않아도 된다.
operations-sorter:method(GET, POST, PUT, DELETE)순으로 정렬,alpha로도 설정 가능하다.tags-sorter: 나중에 설명 할 기능의 tag 의alpha, 알파벳 순으로 정렬한다.display-request-duration: swagger-ui 기능에는 서버에 요청을 쉽게 보낼 수 있는 기능이 있는데, 요청을 보낼 때 요청의 소요 시간을 표시하게 된다.
Swagger Configuration
Configuration 에 굳이 안해도 annotation 으로도 할 수 있지만, 컨트롤러 쪽의 위에 텍스트가 대량으로 쳐져서 컨트롤러 클래스의 코드를 볼 때 어디를 봐야할 지 한 눈에 안들어올 수 있으므로, 필자는 Configuration 에 등록하도록 했다. annotation 으로도 공부해보는 것을 추천한다.
우선 Info model 부터 보자.
Info Model
import io.swagger.v3.oas.models.info.Info;models 패키지를 import 해야 한다(annotations 을 import 하면 동작 안한다).
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("쇼핑몰 API문서")
.version("1.0.0")
.description("쇼핑몰 프로젝트의 REST API ")
.contact(new Contact()
.name("김개발")
.email("dev@shop.com")
.url("https://shop.com"))
.license(new License()
.name("Apache 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0.html")));
}
}코드 자체가 html 구조의 indent 와 비슷하게 되며, 의미 또한 유사하다. 각 new 하는 객체들은 model 을 나타내며, 모델 각각은 API 를 설명하기 위해 메타데이터들을 가지고 있게 된다. Bean 으로 등록되는 OpenAPI 는 swagger-ui 의 문서를 추상화 한 형태이다.
위 문서는 참고용이다. security config 처럼 builder 형태로 chaining 하며 데이터를 입력하며, OpenAPI 에는 info, servers, components 등의 메서드를 통해 메타데이터들을 집어넣을 수 있다. 위를 우선 실행시키고 swagger-ui/index.html path 로 접속하면 다음과 같이 변경되어 있음을 볼 수 있다.

다음은 입력하여 알려주는게 좋다.
- title
- version
- contact
- license
Server Model
servers 에 여러 환경을 등록하면 Swagger UI에서 드롭다운으로 선택 가능하다.
.servers(List.of(
new Server()
.url("http://localhost:8080")
.description("로컬 개발 서버"),
new Server()
.url("https://dev-api.shop.com")
.description("개발 서버"),
new Server()
.url("https://api.shop.com")
.description("운영 서버")
));가독성을 위해 indent 는 좀 줄였다. 우리 서버는 개발, 테스트, 운영의 URI 가 다르기 때문에 위처럼 명시해줄 수도 있다. 이를 실행하면 다음처럼 뜨게 된다.

주의할 점은 server 가 아니라 servers 라서 iterable 한 객체를 넣어줘야 한다.
Components Model
보안 스키마도 설정할 수 있는데 components 메서드를 통해 설정할 수 있다.
.components(new Components()
.addSecuritySchemes("bearerAuth", // 이름은 자유롭게
new SecurityScheme()
.type(SecurityScheme.Type.HTTP) // HTTP 인증
.scheme("bearer") // Bearer 토큰 방식
.bearerFormat("JWT") // JWT 포맷
.description("JWT 토큰을 입력하세요 (Bearer 제외)")))
// 전역으로 보안 적용 (모든 API에 JWT 필요)
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"));Components 에는 addSecuritySchemes 메서드가 있어서 여기에 SecurityScheme 하나씩 넣어주면 된다. 이를 넣어주기만 하면 안되고, bearerAuth 로 등록된 것들을 SecurityItem 으로 사용이 가능하다. addSecurityItem 으로 전역적인 보안 설정이 가능하며, 여기에 SecurityRequirement 모델로 bearerAuth 의 이름을 가지는 SecurityScheme 를 불러오도록 하자. 최종적으로 실행해보자.
assets/img/swagger-ui-authorize.png
위처럼 뜨게 되며, 클릭시 JWT 토큰을 입력할 수 있는 창도 뜨게 된다.
assets/img/swagger-ui-bearerAuth.png
나중에 여기서 JWT 토큰을 입력하여 요청을 보내볼 것이다.
Swagger Controller
Controller 에 API 들이 들어갈텐데, 이 부분이 가장 문서에서 중요한 데이터일 것이다. 우선 Tag 를 보자.

위처럼 API 단위로 태그를 달 수 있고, 태그들에 따라 UI 에서 분류가 되어 위와 같이 보여지게 된다. 태그는 아래와 같이 코드를 짤 수 있다.
@Tag(
name = "User Management API",
description = "사용자 관리 관련 API 입니다. 생성, 조회, 수정, 삭제 기능을 제공합니다."
)
public interface UserControllerDocs {태그는 @Target({METHOD, TYPE, ANNOTATION_TYPE}) 이기 때문에, 클래스와 메서드에 붙일 수 있다. 이제 메서드를 꾸며보자.
API Method 설명 등록
@Operation(
summary = "모든 사용자 조회",
description = "데이터베이스에 등록된 모든 사용자 정보를 조회합니다."
)
// ...
ResponseEntity<?> getAllUsers();설명 등록을 위해서 @Operation 애노테이션을 사용할 수 있고, 아래와 같이 위치되게 된다. API 를 열면 가장 최상위에 보여질 텍스트가 된다.

API 에 응답도 예시로 줄 수 있는데, @ApiResponses 를 사용하면 된다.
@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = UserResponse.class)
)
),
@ApiResponse(
responseCode = "500",
description = "서버 내부 오류",
content = @Content() // 빈 응답
)
})위에서 ApiResponse 에 content 부분은 아래 사진의 중간에 보이는 Media Type이 나오는 부분이다. schema 를 클릭하면 @Schema 로 등록했던 UserResponse.class 에 들어갈 데이터 타입들을 볼 수 있다.

조금 더 복잡한 요청이 있는 API를 보자.
@Operation(
summary = "사용자 배치 생성",
description = "여러 사용자를 한 번에 생성합니다."
)
@RequestBody(
description = "생성할 사용자 목록",
required = true,
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = UserRequest.class),
examples = { // 여러 예시 제공
@ExampleObject(
name = "2명 생성",
value = "[{\"name\":\"홍길동\",\"email\":\"hong@test.com\",\"age\":25}," +
"{\"name\":\"김철수\",\"email\":\"kim@test.com\",\"age\":30}]"
),
@ExampleObject(
name = "1명 생성",
value = "[{\"name\":\"이영희\",\"email\":\"lee@test.com\",\"age\":28}]"
)
}
)
)
ResponseEntity<?> createUsers(List<UserRequest> requests);
이제 DTO 에서 @Schema 로 애노테이션을 달아줘서 example 과 설명을 달아보자.
Swagger DTO Class
DTO 클래스는 API 요청에 빼놓을 수 없는 중요 데이터이다. 이를 토대로 송수신하며, 여기에서도 사용자에게 어떤 요청 데이터를 보내야 할지 어떤 응답이 올 지를 보여줄 수 있다.
public record UserResponse(
@Schema(
description = "사용자 ID",
example = "1"
)
Long id,
@Schema(
description = "사용자 이름",
example = "홍길동"
)
String name,
@Schema(
description = "사용자 이메일",
example = "email@email.com"
)
String email,
@Schema(
description = "나이",
example = "1"
)
Integer age,
@Schema(
description = "활성화 여부",
example = "true"
)
Boolean active,
@Schema(
description = "생성 일시",
example = "2099-01-01T10:00:00"
)
LocalDateTime createdAt
) { }@Schema 를 달아주면 ExampleValue 에는 example 에 해당하는 값이 들어가게 된다.

수치형 데이터 Schema 예제
@Schema(
description = "사용자 나이",
example = "25",
minimum = "1",
maximum = "150"
)정규표현식 Schema 예제
@Schema(
description = "휴대폰 번호",
example = "010-1234-5678",
pattern = "^010-\\d{4}-\\d{4}$"
)Swagger Security
이전에 Configuration 에 선언했던 security schema 로 bearerAuth 를 등록했었다. 전역 보안 설정을 풀고 특정 메서드에서만 bearerAuth 를 사용하여 JWT 인증을 해야 실행할 수 있도록 해보자.
@Operation(
summary = "사용자 배치 생성",
description = "여러 사용자를 한 번에 생성합니다.",
deprecated = false,
hidden = false,
security = @SecurityRequirement(name = "bearerAuth")
)사용자를 대량으로 생성하는 API 에 @Operation 의 security 속성을 넣어 SecurityRequirement 애노테이션을 사용하여 넣어줄 수 있다. 그러면 다음과 같이 API 에 자물쇠가 걸리는 것을 볼 수 있다.

위처럼 문서만 작성한 것이지 Security 로 authorize 기능을 넣어줘야 된다. 지금은 기능이 없고 껍데기만 작성된 것이다.