티스토리 뷰

반응형

일반적으로 여러명이서 개발하는 서비스에서 설계에 작성된 모든 테이블과 1:1로 매칭되어 API를 만드는 일은 거의 없습니다. 그렇기 때문에 해당 API서버가 어떤 명세를 가지고 데이터를 통신하는지 문서작업이 필요하고, 이를 클라이언트 개발자들이 보고 화면에 출력하기 위해 사용하는 명세작업을 기반으로 개발이 진행됩니다.

 

Swagger는 이러한 명세 작업을 서버/클라이언트 개발자의 수기가 아닌 코드로 대체해주는 라이브러리 DI로써 유용하게 사용될 수 있습니다.


가장 먼저 작업할 일은 의존성을 추가하는 일입니다. 

 

1. 의존성 추가

compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0'

 

그 다음으로 프로젝트에 Swagger 설정을 진행합니다. SwaggerConfig 내에서 대부분의 설정이 가능합니다. 

2. SwaggerConfig 설정하기

@Configuration
public class SwaggerConfig {

    @Value("${project.version}")
    @Getter
    private String projectVersion;

// 기본적으로 빈 주입을 실행하고 해당 Docket 에서 대부분의 설정이 진행됩니다. 
    @Bean
    public Docket api(){

        // 전역으로 사용할 Swagger 변수에 대한 설정입니다.
        TypeResolver resolver = new TypeResolver();


        return new Docket(DocumentationType.OAS_30)
            .consumes(getConsumeContentTypes()) // api consume 정의
            .produces(getProduceContentTypes()) // api produce 정의
            .useDefaultResponseMessages(false) // 기본 메시지 사용여부
            .select()
            .apis(RequestHandlerSelectors.any()) // 보여줄 api method 의 범위 지정 (GET, POST, PUT등)
            .paths(PathSelectors.ant("/api/**")) // 보이는 api path AntMatcher 범위
            .build()
            .apiInfo(apiInfo()) // 명세서에 보이는 정보
            .securityContexts(Arrays.asList(securityContext())) // 적용할 보안 정보
            .securitySchemes(Arrays.asList(apiKey())); // 토큰 인증에 대한 정보
    }

    //프로젝트 정보
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("프로젝트 타이틀")
            .description("해당 내용은 API 문서입니다. 인증이 필요한 경우 아래 Authorize 버튼을 눌러 요청 토큰을 넣어주세요.")
            .version(projectVersion)
            .build();
    }

    // api consume 정보입니다. 들어오는 데이터 타입을 정의할 때 주로 씁니다.
    private Set<String> getConsumeContentTypes() {
        Set<String> consumes = new HashSet<>();
        consumes.add("application/json;charset=UTF-8");
        consumes.add("application/x-www-form-urlencoded");
        return consumes;
    }

    // api produce 정보입니다. 서버에서 반환하는 데이터 타입을 정의합니다.
    private Set<String> getProduceContentTypes() {
        Set<String> produces = new HashSet<>();
        produces.add("application/hal+json;charset=UTF-8");
        return produces;
    }

    // 보안에 대한 내용입니다.
    private SecurityContext securityContext() {
        return springfox.documentation.spi.service.contexts.SecurityContext.builder()
            .securityReferences(defaultAuth()).forPaths(PathSelectors.any()).build();
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
    }
    
    // Json Web Token 에 대한 설정입니다.
    @Bean
    public HttpAuthenticationScheme jwt() {
        return HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("JWT Token").build();
    }

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


}

기본적인 내용은 주석으로 달았습니다. Produce / Consume 에 대한 정보를 자세히 보시려면 아래 링크를 참고해주세요.

https://mungto.tistory.com/438

 

[Spring] consumes와 produces의 차이

Mapping을 할때 우리는 받고싶은 데이터를 강제를 함으로써 오류상황을 줄일 수 있다. 이걸 위해 사용하는 것 중 하나가 Media Types이다. 들어오는 데이터와 나가는 데이터를 정하여 처리를 할 수 있

mungto.tistory.com

 

 

3. ApiModelProperty 설정하기

이제 Response Payload 로 넘어갈 DTO 데이터의 정보를 클라이언트 개발자에게 보여주어야할 내용에 대한 정의를 적어보려 합니다. 

@Getter
@Setter
@ApiModel
public class PaginationRequest {
    @ApiModelProperty(value = "페이지 번호(0 ~ )")
    private Integer page;

    @ApiModelProperty(value = "페이지 크기")
    private Integer size;

    @ApiModelProperty(value = "정렬 방법 (ASC|DESC), 기본 ASC")
    @Builder.Default
    private String sort = "ASC";
    
    @ApiModelProperty(value = "정렬 컬럼명")
    private String orderBy;
    
    // 기본 Order By 컬럼명
    public String getOrderBy() {
        if(this.orderBy == null) {
            return "id";
        }
        return this.orderBy;
    }
}

 

4. Api 설정하기 - 컨트롤러

다음으로 UI 로 보여야 하는 화면 컨트롤러에 대한 API 명세작업을 진행합니다. 이 작업이 이뤄지면 이제 명세서에도 추가가 되고 클라이언트 개발자가 화면에서 볼 수 있는 구성까지 끝납니다. 

@RestController
@RequestMapping(value = "/api/jwt", produces = "application/hal+json;charset=utf8")
@RequiredArgsConstructor
public class JwtRestController implements JwtAuthInterface {

    ...

}
@Api(tags = "JWT 발급")
interface JwtAuthInterface {

    @ApiOperation(value = "인증 토큰 발급", notes = "로그인 사용자의 액세스 토큰과 리프레시 토큰을 발급합니다.")
    ResponseEntity createAuthenticationToken(AuthenticationRequest authenticationRequest);
    
}

기본적인 Swagger 문법을 사용하려면 @Api 를 사용하고 태그의 내용을 추가해야 합니다. 기본값으로는 화면에서 인터페이스 또는 클래스 명이 보이게 됩니다. (JwtRestController 라고 보입니다.) 

tags 를 설정하였을 때와 그렇지 않은 경우

 

다음으로 지정할 것은 @ApiOpertaion 내용입니다. 해당 내용이 들어가는 경우 Swagger 내의 tags 다음 아이템의 내용을 확인할 수 있으며, value 내용만 입력하여도 됩니다. 

 

4-1. Response 내에 옵션 추가하기 

아래의 내용은 이제 Response 내용에 대한 값을 설정하는 방법 중 하나입니다. Request Parameter 방법으로 PathVarible을 사용하는 경우입니다. 

@ApiImplicitParams(value = {
    @ApiImplicitParam(name = "pathVariableReq1", value = "패스값1", paramType = "path", dataType = "String", dataTypeClass = String.class),
    @ApiImplicitParam(name = "pathVariableReq2", value = "패스값2", paramType = "path", dataType = "Long", dataTypeClass = Long.class),
})
@ApiOperation(value = "인증 토큰 발급", notes = "패스 값으로 받는 방법")
ResponseEntity createAuthenticationToken(String pathVariableReq1, Long pathVariableReq2);

아래 코드로 적용하고 나온 실제 요청값 정의

@ApiImplicitParams(value = {
    @ApiImplicitParam(name = "companyName", value = "회사 영문명", paramType = "path", dataType = "String", dataTypeClass = String.class),
})

 

 

4-2. 서버의 응답 상태값 표현하기

아래의 내용은 서버에서 처리하고 적용되는 응답값을 상태코드로 보여줄 수 있는 방법입니다. 

@ApiOperation(value = "스웨거 샘플 ", notes = "서버의 응답값을 보여줍니다.")
@ApiResponses({
    @ApiResponse(responseCode = "200", description = "성공"),
    @ApiResponse(responseCode = "401", description = "인증 실패"),
    @ApiResponse(responseCode = "404", description = "회원 정보 없음"),
    @ApiResponse(responseCode = "500", description = "서버 에러"),
})
public void useSwaggerApiResponseAndCode(AppRequest request);

Responses 를 열어보면 아래에 서버 상태코드를 표시해줄 수 있습니다.

 


 

5. 결과물 확인하기 

이제 자바 코드로 작성된 웹페이지를 확인할 차례입니다. 서버가 8080 포트에서 출력되었다면 아래 링크로 들어가서 확인하실 수 있습니다.

http://localhost:8080/swagger-ui/index.html#/
반응형
댓글
공지사항