Swagger는 API를 문서화하는 데 사용되는 오픈 소스 프레임워크로, API 문서화를 자동화하여 개발 생산성을 향상시킬 수 있다. API를 엑셀, 가이드 문서 등을 통해 관리하는 방법은 주기적인 업데이트가 필요하기 때문에 관리가 쉽지 않고 별도의 시간이 소요된다. 따라서 Swagger를 사용하여 간편하게 API 문서를 관리하며 API를 테스트할 수 있다.
본 글은 Spring Boot 2.x 버전에서 작성되었다.
먼저 사용을 위해 의존성을 추가한다.
유의 : Spring Boot 3.x + Swagger
Spring Boot 3.x 버전부터 Swagger의 패키지 경로가 달라져 어느 버전에 매칭해주어야 하는 지 의견이 분분하다. 해당 이슈에 대한 해결책을 기록한 좋은 글이 있어 첨부한다.
build.gradle
dependenciees {
// ...
implementation 'org.springdoc:springdoc-openapi-ui:1.6.15'
implementation 'io.springfox:springfox-swagger2:2.9.2'
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
// ...
}
그 후 환경설정을 위해 다음과 같은 SwaggerConfig
클래스를 생성해준다.
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI studyAPI() {
Info info = new Info()
.title("Server WorkBook API")
.description("Server WorkBook API 명세서")
.version("1.0.0");
String jwtSchemeName = "JWT TOKEN";
// API 요청헤더에 인증정보 포함
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName);
// SecuritySchemes 등록
Components components = new Components()
.addSecuritySchemes(jwtSchemeName, new SecurityScheme()
.name(jwtSchemeName)
.type(Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT"));
return new OpenAPI()
.addServersItem(new Server().url("/"))
.info(info)
.addSecurityItem(securityRequirement)
.components(components);
}
}
Spring Boot에서 Swagger를 사용할 때 설정에는 Docket
과 OpenAPI
라는 두 가지 클래스가 사용되는데 OpenAPI
는 Swagger 3.0 버전부터 도입된 새로운 스펙이다.
일반적으로 Swagger 2.x 버전에서는 Docket
을 사용하고, Swagger 3.0 이상에서는 OpenAPI
를
사용하는 것이 권장된다. 두 방법 모두 API 문서를 생성하고 설정하는 데 사용된다.
글에 사용된 예제 코드는 이미 편의상 작성된 것을 그냥 사용하여 2.x 버전임에도 OpenAPI
를 이용하였다. 이 점에 유의하자.
이제 /swagger-ui.html
경로를 통하여 Swagger API 문서 페이지를 확인할 수 있다.
Swagger에서 API 문서를 위해 사용되는 어노테이션들을 정리해보자.
@ApiOperation
으로 해당 Controller 의 method 설명을 추가할 수 있다.
@ApiOperation(
value = "사용자 정보 조회",
notes = "사용자의 ID를 통해 사용자 정보를 조회한다.")
@GetMapping("/user/{id}")
public UserDTO getUser(@PathVariable(name = "id") String id) {
User user = userService.findById(id);
return UserConverter.toUserDTO(user);
}
이 어노테이션을 사용해 해당 API 호출에 필요한 Parameter들의 설명을 기록할 수 있다.
@ApiOperation(
value = "사용자 정보 조회",
notes = "사용자의 ID를 통해 사용자 정보를 조회한다.")
@ApiImplicitParam(
name = "id",
value = "사용자 아이디",
required = true,
dataType = "string",
paramType = "path",
defaultValue = "None")
@GetMapping("/user/{id}")
public UserDTO getUser(@PathVariable(name = "id") String id) {
User user = userService.findById(id);
return UserConverter.toUserDTO(user);
}
dataType, paramType. required
의 경우 해당 name
을 바탕으로 정보가 자동으로 채워져 생략 가능하다. 만약 해당 메서드의 Parameter가 복수일 경우 @ApiImplicitParams
를 이용하여 복수 개의 @ApiImplicitParam
을 작성할 수 있다.
@ApiOperation(
value = "자격증 정보 조회"
, notes = "자격증의 ID를 통해 자격증의 정보를 조회한다.")
@ApiImplicitParams(
{
@ApiImplicitParam(
name = "id"
, value = "자격증 아이디"
, required = true
, dataType = "string"
, paramType = "path"
, defaultValue = "None"
)
,
@ApiImplicitParam(
name = "fields"
, value = "응답 필드 종류"
, required = false
, dataType = "string"
, paramType = "query"
, defaultValue = ""
)
})
@GetMapping("/licenses/{id}")
public UserDTO getLicense(@PathVariable(name = "id") String id, @RequestParam(name = "fields", required = false) String fields) {
return userService.findUserInfoById(id);
}
이 어노테이션을 사용해 해당 메서드의 응답에 대한 설명을 작성할 수 있다.
@ApiResponse(code = 200, message = "성공입니다.")
@GetMapping("/example")
public String test(){
return "test";
}
복수 개의 응답에 대한 설명은 @ApiResponses
를 이용할 수 있다.
@ApiResponses({
@ApiResponse(code = 200, message = "성공입니다")
@ApiResponse(code = 400, message = "올바르지 않은 접근입니다")
})
@GetMapping("/example")
public String test(){
return "test";
}
위 사진에서의 기본 응답 메시지를 삭제하고 싶다면 SwaggerConfig
설정 시 아래 예제 코드와 같이 구성해주면 된다. @ApiResponse
로 설정하지 않은 응답들이 사라진다.
Docket
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false) // 이 부분을 설정
.select()
.apis(RequestHandlerSelectors.basePackage("your.base.package"))
.paths(PathSelectors.any())
.build();
}
}
OpenAPI
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("Your API").version("1.0"))
.externalDocs(new ExternalDocumentation()
.description("Additional documentation")
.url("https://example.com"))
.defaultResponseMessages(Collections.emptyList()); // 기본 응답 메시지 비활성화
}
}
DTO의 필드에 대한 설명을 추가할 수 있다.
@ApiResponses({
@ApiResponse(code = 200, message = "성공입니다")
@ApiResponse(code = 400, message = "올바르지 않은 접근입니다")
})
@GetMapping("/example")
public String test(TestDTO testDTO){
return "test";
}
TestDTO
@Getter
@AllArgsConstructor
public class TestDTO {
@ApiParam(value = "사용자 ID", required = true)
private String id;
@ApiParam(value = "사용자 이름")
private String name;
@ApiParam(value = "token 갱신 값")
private String refreshToken;
}
Controller에서 Parameter에 적용할 수도 있으나 권장되지 않는다.
이 어노테이션을 DTO 필드에 추가하면 해당 필드의 예제 데이터를 고지할 수 있다.
@Getter
@AllArgsConstructor
public class TestDTO {
@ApiModelProperty(
name = "id",
example = "mj1111"
)
@ApiParam(value = "사용자 ID", required = true)
private String id;
@ApiModelProperty(
example = "김아무개"
)
@ApiParam(value = "사용자 이름")
private String name;
@ApiParam(value = "token 갱신 값")
private String refreshToken;
}
name
은 생략이 가능하다.
@ApiResponses({
@ApiResponse(code = 200, message = "성공입니다.")
, @ApiResponse(code = 400, message = "접근이 올바르지 않습니다.")
})
@ApiImplicitParam(
name = "id"
, value = "사용자 아이디"
, required = true
, dataType = "string"
, paramType = "path"
, defaultValue = "None")
@GetMapping("/notices/{id}")
public String test(UserDTO userDTO) {
return "test";
}
위 코드에서는 id
만 표기하면 되는데, Parameter가 DTO의 형태이기 때문에 관련한 모든 Parameter가 노출되게 된다. @ApiIgnore
를 추가하면 @ApiImplicitParam
으로 선언하지 않은 Parameter 정보들을 UI 상에 표현되지 않게 할 수 있다.
@ApiResponses({
@ApiResponse(code = 200, message = "성공입니다.")
, @ApiResponse(code = 400, message = "접근이 올바르지 않습니다.")
})
@ApiImplicitParam(
name = "id"
, value = "사용자 아이디"
, required = true
, dataType = "string"
, paramType = "path"
, defaultValue = "None")
@GetMapping("/notices/{id}")
public String test(@ApiIgnore UserDTO userDTO) {
return "test";
}
한편, 메서드의 return type
앞에 명시하여 해당 메서드를 아예 UI 상에 노출되지 않게 구성할 수도 있다.
@ApiResponses({
@ApiResponse(code = 200, message = "성공입니다.")
, @ApiResponse(code = 400, message = "접근이 올바르지 않습니다.")
})
@ApiImplicitParam(
name = "id"
, value = "사용자 아이디"
, required = true
, dataType = "string"
, paramType = "path"
, defaultValue = "None")
@GetMapping("/notices/{id}")
public @ApiIgnore String test(UserDTO userDTO) {
return "test";
}
SwaggerConfig
에서 2.0 버전의 경우 Docket
의 apiInfo(ApiInfo Type)
, 3.0 버전의 경우 OpenAPI
의 info(Info info)
를 작성하여 Swagger UI 기본 화면의 API 설명 문구 등을 커스텀할 수 있다.