직전 프로젝트에서는 구글 스프레드 시트를 이용해서 API 명세서를 작성했었다. 하지만 좀 더 가시적으로 문서화할 수 있으면 좋을 것 같다는 생각이 계속 들었다. 실제로, 구글 스프레드 시트에 작성된 명세서에 있던 오탈자로 인해 클라이언트 측에서 상당 시간을 낭비한 경우도 있었다. 그래서 API 문서화 도구인 Swagger를 사용해서 API를 문서화 하기로 했다. 잘 정리되어 있는 문서는 팀의 생산성을 높여줄 것이 분명하므로 충분히 가치있다고 생각된다.
Swagger 는 REST API를 설계, 빌드, 문서화 및 사용하는 데 도움이되는 OpenAPI 사양을 중심으로 구축 된 오픈 소스 도구 세트입니다. - About Swagger Specification
Swagger
를 사용하는 이유는 다음과 같다.
Swagger
는 코드 몇 줄만 추가하면 만들 수 있다!Spring REST Docs
는 테스트를 돌리면서 성공하는지 실패하는지 확인하지만 Swagger
는 문서 화면에서 API를 바로 테스트 할 수 있다.우선, build.gradle
에 의존성을 추가해준다(2.9.2 버전 기준).
// swagger
compile 'io.springfox:springfox-swagger2:2.9.2'
compile 'io.springfox:springfox-swagger-ui:2.9.2'
다음으로는 설정 클래스를 정의한 뒤 @EnableSwagger2
어노테이션을 선언해주고 @Bean
어노테이션을 이용해서 Docket
객체를 빈으로 등록해주면 된다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket apiV1() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("groupName1")
.select()
.apis(RequestHandlerSelectors.
basePackage("com.app.edit"))
.paths(PathSelectors.ant("/v1/api/**"))
.build()
.apiInfo(apiInfo());
}
@Bean
public Docket apiV2() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.groupName("groupName2")
.select()
.apis(RequestHandlerSelectors.
basePackage("com.app.edit"))
.paths(PathSelectors.ant("/v2/api/**"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfo(
"Title",
"Description",
"version 1.0",
"https://naver.com",
new Contact("Contact Me", "https://daum.net", "colt@colt.com"),
"Edit Licenses",
"https://naver.com",
new ArrayList<>()
);
}
}
@EnableSwagger2
Swagger2
버전을 활성화 하겠다는 어노테이션이다.Swagger
설정을 할 수 있게 도와주는 클래스이다.useDefaultResponseMessages()
false
로 설정하면 Swagger
에서 제공해주는 응답코드(200, 401, 403, 404)에 대한 기본 메시지를 제거해준다.groupName()
Docket Bean
이 한 개일 경우 생략해도 상관없으나, 둘 이상일 경우 충돌을 방지해야 하므로 설정해줘야 한다.select()
ApiSelectorBuilder
를 생성하여 apis()
와 paths()
를 사용할 수 있게 해준다.apis()
api
스펙이 작성되어 있는 패키지를 지정한다.basepackage
로 지정하여 해당 패키지에 존재하는 API를 문서화 한다.paths()
apis()
로 선택되어진 API중 특정 path 조건에 맞는 API들을 다시 필터링하여 문서화한다.PathSelectors.any()
로 설정하면 패키지 안에 모든 API를 한 번에 볼 수 있다.apiInfo()
ParameterBuilder
+ globalOperationParameters()
parameterBuilder
와 globalOperationParameters()
를 이용해서 아래와 같이 Swagger
의 전체 API에서 보여줄 파라미터를 설정해줄 수도 있다.globalResponseMessage()
globalResponseMessage()
로 모든 operation에 공통된 응답 메시지를 작성해줄 수도 있다.@Bean
public Docket apiV1() {
List<ResponseMessage> responseMessages = new ArrayList<>();
responseMessages.add(new ResponseMessageBuilder()
.code(200)
.message("OK")
.build());
responseMessages.add(new ResponseMessageBuilder()
.code(404)
.message("Not Found Error")
.build());
responseMessages.add(new ResponseMessageBuilder()
.code(500)
.message("Internal Server Error")
.build());
return new Docket(DocumentationType.SWAGGER_2)
.groupName("groupName1")
.select()
.apis(RequestHandlerSelectors.
basePackage("com.app.edit"))
.paths(PathSelectors.ant("/v1/api/**"))
.build()
.apiInfo(apiInfo())
.globalResponseMessage(RequestMethod.GET, responseMessages);
}
코드 작성이 완료되었다면 서버를 실행시킨 뒤, http://localhost:8080/swagger-ui.html 로 들어가면 API가 문서화된 화면을 볼 수 있다.
swagger-ui.html로 접속하는 이유는,
springfox-swagger-ui
가 해당 파일을 만들어주기 때문이다.
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(value = "hello", tags = {"swagger", "v1", "api"})
@RequestMapping("/v1/api")
@RestController
public class SwaggerController {
@ApiOperation(value = "this is test!", notes = "note!!!!!")
@PostMapping("/test")
public String test(@ApiParam(name = "first param", value = "first value", required = true) String input,
@ApiParam(name = "second param", value = "second value", required = false) String input2) {
return "test";
}
}
Swagger
리소스라는 것을 명시해준다.value
: 사용자 지정 이름을 붙일 수 있다. tags
사용시 무시된다.tags
: 사용하여 여러 개의 태그를 정의할 수도 있다.Operation
을 선언한다.value
: API에 대한 요약을 작성한다. 제대로 표시되려면 120자 이하여야 한다.notes
: API에 대한 자세한 설명을 작성한다.name
: 파라미터 이름을 작성한다.value
: 파라미터 설명을 작성한다.required
: 필수 파라미터이면 true
, 아니면 false
를 작성한다.주의사항
API 문서 URL을 알고 있다면 아무나 들어와서 테스트를 할 수도 있다. 따라서 사전에 접근권한의 제한 등을 통해 권한이 있는 사용자만 접근할 수 있도록
Spring Security
등의 설정을 해주어야한다!
안녕하세요 좋은글 감사합니다.
스웨거 설정 올려주신글 보고 있는데요.
http://localhost:8181/swagger-ui.html 접속시
Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. ~
라고 발생하는데 해결 방법을 못찾고 있습니다.
혹시 어느 부분을 봐야 하는지 답변 주시면 정말 감사하겠습니다.
좋은 글 감사합니다!