Framework/Spring

[Spring Boot]Springdoc 적용하기

  • -
반응형

최근 코드드림 프로젝트를 다시 시작하면서 API 명세 작성을 위해 Springdoc을 이용했습니다.

이전에 Springfox Swagger를 이용해본 경험이 있어 이번에는 Springdoc을 선택했고, 어떻게 사용하는지 포스팅을 통해 알아보겠습니다. 

 

※ 테스트 환경
  • Spring Boot 2.7.5
  • Springdoc 1.6.10
  • Gradle

Springdoc

Springdoc은 Spring Boot 프로젝트에 특화된 OpenAPI 3.0 기반 라이브러리입니다. 주요 특징은 다음과 같습니다.

  • Spring Boot와의 강력한 통합 지원
  • Spring MVC 또는 Spring WebFlux 컨트롤러와 자동으로 연동하여 OpenAPI 문서를 생
  • Swagger UI와 OpenAPI 스펙을 기본적으로 포함하여 설정이 간단.
  • Spring 어노테이션(@RestController, @RequestMapping 등)을 사용하여 API 문서를 자동 생성

 

Springfox Swagger의 경우 3.0 버전을 마지막으로 업데이트가 중단(2020.07)된 반면 Springdoc은 최근까지도 업데이트가 진행되고 있습니다. Springfox의 대부분 기능을 지원하고 있고 WebFlux도 지원하기 때문에 최근에는 Springdoc을 추천하고 있는 추세입니다.

그럼 Springdoc을 적용해보겠습니다.

 

1. 의존성 주입

 // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui
 implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.7.0'

 

 

2. Config 추가

OpenAPI를 빈으로 등록하면 Swagger UI가 생성됩니다.

package com.app.marryme.common.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.security.SecurityScheme.Type;
import org.apache.http.HttpHeaders;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringDocsConfig {

    @Bean
    public OpenAPI openAPI() {
        // Header - Authorization Bearer ***
        SecurityScheme securityScheme = new SecurityScheme()
            .type(SecurityScheme.Type.HTTP)
            .scheme("Bearer")
            .bearerFormat("JWT")
            .in(SecurityScheme.In.HEADER)
            .name(HttpHeaders.AUTHORIZATION);
        // Header - Client Secret
        SecurityScheme clientScheme = new SecurityScheme()
            .type(Type.APIKEY)
            .in(SecurityScheme.In.HEADER)
            .name("CLIENT-KEY");

        SecurityRequirement addSecurity = new SecurityRequirement()
            .addList("AccessToken")
            .addList("CLIENT-KEY");

        return new OpenAPI()
            .components(new Components()
                .addSecuritySchemes("AccessToken", securityScheme)
                .addSecuritySchemes("CLIENT-KEY", clientScheme)
            )
            .addSecurityItem(addSecurity)
            .info(apiInfo());
    }

    private Info apiInfo() {
        return new Info()
            .title("메리미 API 문서")
            .version("1.0.0")
            .description("메리미 API 목록")
            .contact(new Contact()
                .name("CODEDREAM")
                .email("codedream.contact@gmail.com")
                .url("https://codedream.co.kr"));
    }
}

API 호출시 필요한 JWT 토큰과 Client Secret을 정의합니다. 

프로젝트에서는 JWT 토큰을 통해 인증을 하며, 고유의 Client Secret을 부여하여 특정 서비스에서만 요청이 가능하도록 필터링했습니다.

 

 

3. Controller 설명 등록

@Tag@Operation 어노테이션을 이용해 컨트롤러의 설명을 작성합니다.

Request Parameter는 @Parameter 어노테이션을 이용해 설명을 작성합니다.

@Tag(name = "기타 API", description = "안내사항 및 썸네일을 조회, 저장한다.")
@RestController
@RequiredArgsConstructor
@RequestMapping("etc")
public class EtcController {

    private final EtcService etcService;

    @Operation(summary = "안내사항/썸네일 저장", description = "안내사항 및 썸네일을 저장한다.")
    @PostMapping
    public ResponseEntity<MessageDto> saveNotice(
        @RequestBody NoticeDto noticeDto
    ) throws Exception {
        etcService.saveNotice(noticeDto);
        return ResponseEntity.ok()
            .body(new MessageDto("success", ""));
    }

    @Operation(summary = "안내사항/썸네일 조회", description = "안내사항 및 썸네일을 조회한다.")
    @GetMapping("/{cardNo}")
    public ResponseEntity<MessageDto> getNotice(
        @Parameter(description = "카드번호", required = true)
        @PathVariable("cardNo") Long cardNo
    ) {
        NoticeDto noticeInfo = etcService.getNotice(cardNo);
        return ResponseEntity.ok()
            .body(new MessageDto("success", noticeInfo));
    }

}

 

 

4. DTO 설명 등록

@Schema 어노테이션을 이용해 API  호출, 반환에 사용되는 Dto 클래스에 설명을 작성합니다.

example, required 옵션을 통해 예제나 필수 여부도 표현이 가능합니다.

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

    @Schema(description = "카드번호", example = "1", required = true)
    private Long cardNo;
    @Schema(description = "안내사항 제목")
    private String noticeTitle;
    @Schema(description = "안내사항 단독형 사용여부", example = "N")
    private String tabSingleYn;
    @Schema(description = "안내사항 그룹형 사용여부", example = "N")
    private String tabMultiYn;
    private ThumbnailDto thumbnail;
    private NoticeDetailDto singleNotice;
    private List<NoticeDetailDto> noticeList;

}
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ThumbnailDto {

    private Long cardNo;
    @Schema(description = "썸네일 이미지")
    private String thumbImageUrl;
    @Schema(description = "썸네일 제목")
    private String thumbTitle;
    @Schema(description = "썸네일 내용")
    private String thumbContent;

}

 

 

5. Security 설정

Spring Security가 적용된 경우 아래와 같이 예외처리가 필요합니다.

@Bean
@Order(0)
public SecurityFilterChain resources(HttpSecurity httpSecurity) throws Exception {

    return httpSecurity
        // 토큰 인증 방식으로 csrf, 폼로그인 비활성화
        .csrf().disable()
        .formLogin().disable()
        // 인증 제외 경로 설정
        .requestMatchers(matchers ->
            matchers.antMatchers(
                "/css/**", "/images/**", "/scripts/**", "/favicon.ico", "/error"         
                , "/v3/api-docs/**", "/swagger-ui/**"
                , "/swagger-ui.html", "/swagger-resources/**"
            ))
        .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
        .build();
}

 

 

6. 결과 확인

서버 실행 후 /swagger-ui/index.html로 접속하면 아래와 같이 API 문서가 작성되어 있는 것을 확인할 수 있습니다.

1 - Config 설정에 추가된 apiInfo 메소드를 통해 그려집니다.

2 - Config 설정시 추가한 AccessToken과 CLIENT-KEY를 추가합니다. 버튼 클릭 후 팝업을 통해 토큰 값을 입력하고 저장할 수 있습니다.

 

3 - Controller 설정을 통해 작성된 설명을 확인합니다. Try it out을 클릭해 API를 호출할 수 있으며, curl도 확인 가능합니다.

 

Dto 설정을 통해 작성된 내용도 확인할 수 있습니다.

 

*API 전역에 고정 파라미터를 추가하고 싶은 경우

OperationCustomizer를 빈으로 등록하여 사용할 수 있습니다.

@Bean
public OperationCustomizer customizer() {
    return ((operation, handlerMethod) -> operation
        .addParametersItem(new Parameter()
            .in("header")
            .required(true)
            .description("CLIENT-SECRET")
            .name("CLIENT-KEY"))
    );
}

 

Springdoc의 다양한 옵션을 아래 참고문서를 통해 확인해 보세요.

 

참고문서
 

OpenAPI 3 Library for spring-boot

Library for OpenAPI 3 with spring boot projects. Is based on swagger-ui, to display the OpenAPI description.Generates automatically the OpenAPI file.

springdoc.org

 

반응형
Contents

포스팅 주소를 복사했습니다.

이 글이 도움이 되었다면 공감 부탁드립니다.