Swagger

2019-09-12

SpringBoot Swagger2

Swagger란

Swagger란 API 문서를 자동으로 만들어주는 라이브러리 입니다.

Swagger 구현

Gradle

//springfox-swagger2
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
//springfox-swagger-ui
compile group: 'io.springfox', name: 'spxringfox-swagger-ui', version: '2.9.2'

Maven

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

SwaggerConfig.java

@Configuration
@EnableSwagger2
public class SwaggerConfig {
  
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("worker_api_v1")
                .select()
                .apis(RequestHandlerSelectors.any()) // 모든요청
                .paths(PathSelectors.any()) //모든경로
                .build().apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("스웨거 Api")
                .description("스웨거 튜토리얼! API!.")
                .contact(new Contact("민동현", "https://daeakin.github.io/", "mindh890@gmail.com"))
                .version("1.0.0")
                .build();
    }

}




웹에서 스웨거 접속하기.

http://localhost:{port}/swagger-ui.html

기본적으로 SpringBoot에 의해 만들어지는 컨트롤러들만 현재 노출되어있습니다.


apiInfo() 함수에 관한 내용들

private ApiInfo apiInfo() {
    return new ApiInfoBuilder().title("스웨거 Api")
            .description("스웨거 튜토리얼! API!.")
            .contact(new Contact("민동현", "https://daeakin.github.io/", "mindh890@gmail.com"))
            .version("1.0.0")
            .build();
}



문서 작성용 컨트롤러 만들기.

테스트용 RestController 만들기

2개의 클래스를 더 만들어 보겠습니다.

TestController.java

@RestController
public class TestController {

    @GetMapping("/test")
    public TestDto testGetMethod(@RequestBody TestDto testDto) {
        return new TestDto("Test!!",true);
    }
}

TestDto.java

‼️ Swagger 문서화를 위해서는 Getter 메소드가 필요합니다.

public class TestDto {
    private String message;

    private boolean flag;

    public TestDto(String message, boolean flag) {
        this.message = message;
        this.flag = flag;
    }

    public String getMessage() {
        return message;
    }

    public boolean isFlag() {
        return flag;
    }
}

test-controller 추가 및 /test 경로 추가된 모습

이렇게 매핑해준 경로가 스웨거에 추가 됩니다.

필요한 파라미터가 어떤건지도 알려줍니다.

하지만 이 파라미터가 왜 필요하고 어떤 동작을 위해 필요한지는 필드명만 보고는 어려울 수 있습니다.



1. 필드에 설명 붙여주기. @ApiModel @ApiModelProperty

@ApiModel(description = "이 모델은 Test하기 위한 Dto 입니다.")
public class TestDto {
    @ApiModelProperty(notes = "원하는 message 내용을 넣으세요.")
    private String message;
    @ApiModelProperty(notes = "원하는 boolean 값을 넣으세요.")
    private boolean flag;

    public TestDto(String message, boolean flag) {
        this.message = message;
        this.flag = flag;
    }

    public String getMessage() {
        return message;
    }

    public boolean isFlag() {
        return flag;
    }
}

Model 버튼을 눌러주면 이렇게 나옵니다.

2. 컨트롤러가 무슨동작을 하는지 알려주기 @Api

기본적으로 컨트롤러의 설명은 컨트롤러의 클래스이름을 따라갑니다.

이 클래스가 무슨 용도를 위한 클래스인지 설명을 수정해줄 수 있습니다.

@RestController
@Api(description = "테스트 하기위한 TestController 예요!")
public class TestController {

3. API 어떤 동작을 하는지 알려주기. @ApiOperation

기본적으로 API 설명은 메소드이름으로 적혀있습니다.

이것 또한 개발자가 수정해줄 수 있습니다.

@ApiOperation("테스트를 하기위한 Api이예요!")
@GetMapping("/test")
public TestDto testGetMethod(@RequestBody TestDto testDto) {

    return new TestDto("Test!!",true);
}

4. API 호출이 헤더가 필요할 때 @ApiImplicitParams,@ApiImplicitParam

Oauth2를 사용하신다면 Header에 Token을 넘겨야 합니다.

Swagger 문서에 Header를 명시해주기 위해서는 다음과 같이 사용하시면 됩니다.

@ApiImplicitParams({
        @ApiImplicitParam(name = "Authorization", value = "authorization header", required = true,
                dataType = "string", paramType = "header", defaultValue = "bearer cbbb1a6e-8614-4a4d-a967-b0a42924e7ca")
})
@ApiOperation("테스트를 하기위한 Api이예요!")
@GetMapping("/test")
public TestDto testGetMethod(@RequestBody TestDto testDto) {

    return new TestDto("Test!!",true);
}

5. 파라미터에대해 설명해주기 @ApiParam

API가 필요로하는 파라미터에 대해 설명을 해줄 수 있습니다.

@GetMapping("/test")
public TestDto testGetMethod(@ApiParam(value = "Test대한 정보",required = true)@RequestBody TestDto testDto) {

    return new TestDto("Test!!",true);
}

6. 파라미터가 Swagger에 안보이게 하기

파라미터가 여러개 있을 때 원하지 않는 파라미터를 Swagger에서 안보이게 할 수 있습니다.

저는 Oauth2가 받는 파라미터가 보이지 않게 해주고 싶을 때 이용 했습니다.

@GetMapping("/test")
public TestDto testGetMethod(@ApiIgnore Authentication authentication,@RequestBody TestDto testDto) {
    return new TestDto("Test!!",true);
}

7. Advanced Swagger Config

7-1. 패키지 기반 문서화 basePackage

현재 Swagger는 Spring이 자동으로 만들어지는 Controller도 문서에 나타나게 됩니다.

이 Controller를 제외하는 방법을 해보겠습니다.

SwaggerConfig.java

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .groupName("swagger-tutorial_api_v1")
            .select()          								.apis(RequestHandlerSelectors.basePackage("com.donghyeon.swaggertutorial.controller"))
            .paths(PathSelectors.any())
            .build().apiInfo(apiInfo());
}

지정해준 패키지안에 있는 컨트롤러만 문서화하는 설정입니다.


7-2. /api로 시작하는 API만 문서화하기 ant()

RestAPI들은 보통 /api로 시작하는게 보편적입니다.

/api로 시작하는 API들만 문서화 하는 방법을 알아보겠습니다.

SwaggerConfig.java

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .groupName("swagger-tutorial_api_v1")
            .select()           .apis(RequestHandlerSelectors.basePackage("com.donghyeon.swaggertutorial.controller"))
            .paths(PathSelectors.ant("/api/**"))
            .build().apiInfo(apiInfo());
}

이제 맵핑이 /api 로시작하는것만 문서화가 됩니다,

Trouble Shooting

Swagger에 접속했는데 다음과 오류가 나타날 수 있습니다.

java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_191]
	at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_191]
	at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_191]
	at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412) ~[swagger-models-1.5.20.jar:1.5.20]
	at sun.reflect.GeneratedMethodAccessor149.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_191]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_191]
	at
	....

이 문제는 springfox-swagger2 라이브러리 안에 있는 swagger-annotations과 swagger-models의

버전충돌 문제로 보입니다.

이 두개의 라이브러리만 구 버전인 1.5.21을 사용하시면 해결됩니다.

해결방법

Gradle

//springfox-swagger2
compile(group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2') {
    exclude group: 'io.swagger' ,module : 'swagger-annotations'
    exclude group: 'io.swagger' ,module : 'swagger-models'
}

//springfox-swagger-ui
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
// swagger-annotations 1.5.21 / swagger-models 1.5.21
compile group: 'io.swagger', name: 'swagger-annotations', version: '1.5.21'
compile group: 'io.swagger', name: 'swagger-models', version: '1.5.21'

Maven

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
	<exclusions>
		<exclusion>
			<groupId>io.swagger</groupId>
			<artifactId>swagger-annotations</artifactId>
		</exclusion>
		<exclusion>
			<groupId>io.swagger</groupId>
			<artifactId>swagger-models</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>
<dependency>
	<groupId>io.swagger</groupId>
	<artifactId>swagger-annotations</artifactId>
	<version>1.5.21</version>
</dependency>
<dependency>
	<groupId>io.swagger</groupId>
	<artifactId>swagger-models</artifactId>
	<version>1.5.21</version>
</dependency>

참고자료

github 소스보러가기

오류해결 레퍼런스

value 커스터마이징

Swagger 공식사이트

Swagger Docs