자기소개페이지만들기

4. swagger를 통한 문서화

Swagger(스웨거)는 개발자가 REST API 서비스를 설계, 빌드, 문서화할 수 있도록 하는 프로젝트이다.

다른 개발팀과 협업을 진행하거나 이미 구축되어있는 프로젝트에 대한 유지보수를 진행할 경우그리고

백엔드의 API를 호출하는 프론트엔드 프로그램을 제작할 경우 유용하게 사용할수있다.

 

스웨거의 장점으로 적용하기 쉽고 api를 테스트할수 있는 화면을 제공한다.

단점으로는 어노테이션을 추가하는 방식으로 설정해야하는 단점이 있다.

 

이제 프로젝트에 스웨거를 적용해보자

 

1. 스웨거 의존성 추가

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

 

 

2. 스웨거 설정 추가

import com.fasterxml.classmate.TypeResolver;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Pageable;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.AlternateTypeRules;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.Collections;
import java.util.List;

@EnableSwagger2
@RequiredArgsConstructor
@Configuration
public class Swagger2Config {

    private final TypeResolver typeResolver;

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .alternateTypeRules(AlternateTypeRules
                        .newRule(typeResolver.resolve(Pageable.class), typeResolver.resolve(Page.class)))
                .apiInfo(apiInfo())
                .securityContexts(Collections.singletonList(securityContext()))
                .securitySchemes(Collections.singletonList(apiKey()))
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.myintroduce.web.api"))
                .paths(PathSelectors.ant("/api/**"))
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("MY-INTRODUCE REST 프로젝트 API DOC")
                .version("v.1")
                .description("자기소개 페이지 REST 프로젝트의 문서")
                .termsOfServiceUrl("http://ec2-35-168-161-112.compute-1.amazonaws.com/")
                .license("MY-INTRODUCE Licenses")
                .licenseUrl("https://github.com/whdals7337/myintroduce-backend-project")
                .build();
    }

    private ApiKey apiKey() {
        return new ApiKey("JWT", "Authorization", "header");
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth()).build();
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Collections.singletonList(new SecurityReference("JWT", authorizationScopes));
    }

    @Getter @Setter
    @ApiModel
    static class Page {
        @ApiModelProperty(value = "페이지 번호(0..N)")
        private Integer page;

        @ApiModelProperty(value = "페이지 크기", allowableValues="range[0, 100]")
        private Integer size;

        @ApiModelProperty(value = "정렬(사용법: 컬럼명,ASC|DESC)")
        private List<String> sort;
    }
}

 

위의 경우 전체 설정과 swagger ui로 나눠서 설명하도록하겠습니다.

 

api 정보 설정 부분

private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("MY-INTRODUCE REST 프로젝트 API DOC")
                .version("v.1")
                .description("자기소개 페이지 REST 프로젝트의 문서")
                .termsOfServiceUrl("http://ec2-35-168-161-112.compute-1.amazonaws.com/")
                .license("MY-INTRODUCE Licenses")
                .licenseUrl("https://github.com/whdals7337/myintroduce-backend-project")
                .build();
    }

license와 Terms of service의 경우 클릭시 설정한 url로 이동하게 된다.

 

2. Page 파라미터를 위한 Page class

Swagger가 Pageable를 제대로 잡히지 않기 때문에 새로 만들어서 설정하기 위해서 만들었다.

@Getter @Setter
    @ApiModel
    static class Page {
        @ApiModelProperty(value = "페이지 번호(0..N)")
        private Integer page;

        @ApiModelProperty(value = "페이지 크기", allowableValues="range[0, 100]")
        private Integer size;

        @ApiModelProperty(value = "정렬(사용법: 컬럼명,ASC|DESC)")
        private List<String> sort;
    }

 

3. Spring Security 설정

자기소개 페이지가 jwt를 통해서 인증, 인가를 설정해놨기 때문에 swagger에도 해당 설정을 잡아준 부분이다.

private ApiKey apiKey() {
        return new ApiKey("JWT", "Authorization", "header");
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth()).build();
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Collections.singletonList(new SecurityReference("JWT", authorizationScopes));
    }

 

4. swagger 문서 api 설정

@Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .alternateTypeRules(AlternateTypeRules
                        .newRule(typeResolver.resolve(Pageable.class), typeResolver.resolve(Page.class)))
                .apiInfo(apiInfo())
                .securityContexts(Collections.singletonList(securityContext()))
                .securitySchemes(Collections.singletonList(apiKey()))
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.myintroduce.web.api"))
                .paths(PathSelectors.ant("/api/**"))
                .build();
    }
    

useDefaultResponseMessages: 기본 응답 메세지 설정

alternateTypeRule: Pageable 클래스를 Page 클래스로 타입을 대체하도록 규칙 설정

apiInfo: 앞서 설정한 api 정보를 셋팅

apis(RequestHandlerSelectors.basePackage("com.myintroduce.web.api")) : swagger를 적용할 패키지 설정

path: swagger를 적용할 주소 패턴을 셋팅

 

 

파라미터 관련 설정

 

import com.myintroduce.domain.FileInfo;
import com.myintroduce.domain.entity.member.Member;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberRequestDto {

    @ApiParam(value = "대민 페이지 상단 코멘트", required = true, example = "안녕하세요. 백엔드개발자를 꿈꾸는 유종민입니다.")
    private String comment;

    @ApiParam(value = "대민페이지 Introduction 헤더", required = true , example = "개발자를 꿈꾸다!")
    private String subIntroduction;

    @ApiParam(value = "대민페이지 Introduction 상세 내용", required = true, example = "대학교에서 프로젝트를 경험하며 개발자를 꿈꾸게 되었습니다.")
    private String introduction;

    @ApiParam(value = "대민페이지 하단 연락처", required = true, example = "010-xxxx-xxxx")
    private String phoneNumber;

    @ApiParam(value = "대민페이지 하단 이메일", required = true, example = "uok0201@gmail.com")
    private String email;

    public Member toEntity(String filePath, String originalName, String fileUrl, String selectYN) {
        return  Member.builder()
                .comment(comment)
                .fileInfo(new FileInfo(filePath, originalName, fileUrl))
                .subIntroduction(subIntroduction)
                .introduction(introduction)
                .phoneNumber(phoneNumber)
                .email(email)
                .selectYN(selectYN)
                .build();
    }
}

 

value : 설명

required : 파라미터의 필수 여부

exampel : 기본값 설정

 

spring security를 사용하는 경우

해당 버튼 클릭시 

 

본인이 적용한 방식의 인증을 요구합니다. 위 사진의 경우 jwt 토큰 값을 요구하는 것으로 인증, 인가가 필요한 요청을 할경우 인증후 테스트가 가능합니다.

 

 

github.com/whdals7337/myintroduce-backend-project

 

whdals7337/myintroduce-backend-project

Contribute to whdals7337/myintroduce-backend-project development by creating an account on GitHub.

github.com