Studio u by kingjakeu This is hello from jakeu

Swagger 적용기

API 개발을 할 때, Back-end의 API를 Front 혹은 Third-party에서 적용해야 할 때가 있다. Doc 파일 혹은 Wiki 같은 형태로 API specification을 제공 해도 되겠지만, 문서를 위한 작업은 언제나 재미없고 의욕이 떨어진다.

따라서 Swagger를 통해 보다 쉽고 읽기 편한 API Documentation을 제공해보자.

아래의 코드의 전체 코드는 github에서 확인 가능하다.

의존성 추가

Gradle을 사용할 경우 build.gradle에 Swagger 관련 dependency를 추가해준다.

    implementation 'io.springfox:springfox-swagger2:2.6.1'
    implementation 'io.springfox:springfox-swagger-ui:2.6.1'

Maven을 사용할 경우 pom.xml에 관련 dependency를 추가한다.

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

Swagger Configuration

Swagger의 구성은 Docket Bean이 기준이 되어 설정된다. 따라서 Docket Bean의 정의가 우선이다.

Docket Bean이 정의 된 다음,

  • select() 메소드를 통해 Swagger-ui에 나타날 EndPoint들을 ApiSelectorBuilder의 인스턴스를 생성하여 제어한다.
  • ApiSelectorBuilder를 통해 선택 될 Request와 Path들은 각각 RequestHandlerSelectorsPathSelectors로 설정한다.

Docket 구성 방법

  1. 일단 Swagger configuration이 들어갈 swagger package를 하나 만든 후,
    swagger-7

  2. SwaggerConfiguration.java를 생성한다.

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any()) // Request 필터링
                .paths(PathSelectors.any()) // url 필터링
                .build();
    }
}
  1. RequestHandlerSelectors를 통해 swagger에 나타날 Reqeust들을 필터링 해 줄 수 있다.

  2. PathSelectors를 통해 swagger에 나타날 API url들을 필터링 할 수 있다.
    예를 들어, paths(PathSelectors.ant("/member/**"))라고 정의 하면, url에 /member/~를 가진 api만 swaggger에 노출된다.

간단한 API 작성

Swagger 테스트를 위해 간단한 Controller, Dto, Domain 그리고 Dao를 작성한다.

@RestController
@RequestMapping("/member")
@RequiredArgsConstructor
public class MemberController {

    private final MemberRepository memberRepository;

    @PostMapping("/signup")
    public void signUpMember(@RequestBody MemberSignUpRequestDto dto){
        this.memberRepository.save(dto.toEntity());
    }
}
@Getter
@Setter
@NoArgsConstructor
public class MemberSignUpRequestDto {
    private String userName;
    private String password;

    public Member toEntity(){
        return Member.builder()
                .userName(this.userName)
                .password(this.password)
                .build();
    }
}
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(updatable = false)
    private Long id;

    @Column(updatable = false, nullable = false, unique = true)
    private String userName;

    @Column(nullable = false)
    private String password;

    @Builder
    public Member(String userName, String password){
        this.userName = userName;
        this.password = password;
    }
}
public interface MemberRepository extends JpaRepository<Member, Long> {
}

이렇게 간단한 API를 구성하고 프로젝트를 빌드한다.

Swagger 확인

  1. 이제 http://localhost:8080/swagger-ui.html에 들어가면 Swagger에 방금 작성한 Member Controller를 확인 할 수 있다. swagger-1

  2. Member Controller를 클릭하면 Member Controller에 정의된 API들을 볼 수 있다. swagger-2

  3. 각 API를 눌러보면 해당 Request를 Test까지 해볼 수 있다. 결과 값 또한 확인 가능하며, 별도의 설정 없이 API Test를 할 수 있다. swagger-3 swagger-4

그 외 Tips

  • 만약 모든 API에서 설정되어야 하는 공통 Header 값 같은 공통 파라미터 value가 있다면 Docket에 globalOperationParameters를 통해 설정 해줄 수 있다.
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
    @Bean
    public Docket api(){
        List<Parameter> globalParameter = new ArrayList<>();
        globalParameter.add(new ParameterBuilder()
                .name("Content-Type")
                .description("")
                .parameterType("header")
                .required(true)
                .defaultValue("application/json")
                .modelRef(new ModelRef("String"))
                .build()
        );

        return new Docket(DocumentationType.SWAGGER_2)
                .globalOperationParameters(globalParameter)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }
}

swagger-5

  • 추가적으로 @ApiOperation을 통해 각 API 별 설명을 추가 할 수 있다.
@RestController
@RequestMapping("/member")
@RequiredArgsConstructor
public class MemberController {

    private final MemberRepository memberRepository;

    @PostMapping("/signup")
    @ApiOperation(value = "회원 가입")
    public void signUpMember(@RequestBody MemberSignUpRequestDto dto){
        this.memberRepository.save(dto.toEntity());
    }
}

swagger-6

@ApiOperation(value = "")외에도 많은 것들을 달아 줄 수 있으니, 추가 기능들은 ApiOperation 어노테이션 내부를 살펴보길 바란다.