스웨거 적용기

최지환·2023년 5월 23일
0

졸업작품-동네줍깅

목록 보기
1/11


기존에 진행하던 프로젝트와 다르게 졸업작품은 프론트앤드 개발자 1명, 백앤드 개발자 2명 총 3명의 협업을 해야한다.

본격적으로 프로젝트를 진행하기에 앞서서, 기본적으로 설정을 해야할 것들을 정하던 중, 프론트앤드 개발자 분이 swagger 나 restdocs 적용했으면 좋을 것 같다는 의견을 내주셨다.

사실 기존에 진행하던 프로젝트에서 스웨거를 적용해볼까? 라는 생각도 했었는데, 미루다보니 적용을 못했고, 솔직히 조금 귀찮았었다.

그래서 이번 졸업작품 프로젝트에서는 개발 초기 부터 Swagger 혹은 Restdocs 를 적용해보기로 하였다.

그래도 일단 이 기술들이 무엇인지 찾아보았고, 왜 적용해야하는지 다시 한번 고민해보면서 정리를 하였다.

Swagger

간단하게 설명하자면 API 문서를 자동으로 만들어 주는 라이브러리다. 어노테이션을 통해 생성된 API를 문서내에서 parameter 조작을 통해서 바로 실행할 수 있다.

Spring REST Docs

RESTfull 서비스의 문서화를 도와주는 도구이다. Spring 테스트로 생성된 자동 생성 문서를 통해 api를 실행한다.

각각의 장단점을 살펴보자면

Swagger 장단점

장점

  • 테스트 코드를 작성하지 않아도 어노테이션을 통해서 api 문서를 간단하게 작성 가능
    → 어노테이션만 달면 자동으로 문서가 생성되기 때문에 RestDocs 와 비교하여 쉽게 문서화 가능
  • API 를 통해 Parameter, 응답 정보, 예제 등 Spec 정보 전달이 용이
  • 실제로 사용되는 Parameter로 테스트가 가능

단점

  • 구현 코드에 swagger를 사용하기 위한 어노테이션을 추가해야한다.

RestDocs 장단점

장점

  • 구현 코드에 문서화를 위한 어노테이션을 작성하지 않아도 됨.
  • 테스트 코드를 통해 문서화를 하기 때문에, 테스트코드 작성을 강제할 수 있음

단점

  • 테스트 코드 작성 시 문서화가 가능하기 때문에, 테스트 코드 관리를 지속적으로 해줘야함
    (단점이라기엔 관점에 따라 애매할 수도 있습니다.)

  • Api call을 통한 인수테스트를 진행 하는 과정에서, Controller Layer Test 로 RestDocs 생성을 한다면 중복되는 테스트가 존재함


결론 - swagger 를 채택

이유

  • Api call을 직접 할 수 있기 때문에, postman 을 통해 테스트 하는 불편한 과정이 없어질 것이라 판단
  • 졸업작품 특성 상 정해진 기간안에 개발을 해야하기 때문에, 어노테이션 기반으로 간편하게 문서를 만들 수 있기는 장점이 너무 크게나 느껴짐.
  • 프런트 개발자 분이 swagger 적용을 원하셨기 때문에 현업 관점에서도 좋다고 생각함.

Swagger 적용

swagger에 대해 추가적으로 더 알아보기 위해서

API Documentation & Design Tools for Teams | Swagger

공식 사이트에 들어가서 이것저것 찾아보았다.

지원해주는 기능으로는

  • API 디자인
  • API 빌드
  • API 문서화
  • API 테스팅
  • API 표준화

가 있다고한다.


SpringBoot 환경에서 swagger 를 사용하기 위해서는 springfox-swagger 혹은 springdoc 를 사용해야한다고 한다.

이 둘에 대해 알아보기로 했다.

우선 https://mvnrepository.com/ 에 접속해 각각의 라이브러리에 대한 서칭을 조금 해보았다.

Springfox

springfox 라이브러리는 2020년 7월 14일 기준으로 업데이트가 되지 않고있다.

SpringDoc OpenApi

반면에 Springdoc OpenApi 는 비교적 현재인 2022 년 10월 16일 까지 업데이트가 이루어져있다.

업데이트 시기만 봐도 SpringDoc OpenApi를 사용하는 것이 더 좋다는 결론이 나왔기 때문에, springDoc OpenApi를 사용하기로 했다.

그래도 차이점에 대해서 추가적으로 더 알아보았는데,

springDoc 은 springfox 가 2년동안 지원하지 않는 기간 동안 webflux 를 지원하도록 업데이트가 되었다고 한다.
Springdoc 는 @Tag 어노테이션을 통해서 중복되는 어노테이션들을 관리할 수 있다고한다.

또한 api간 정렬을 할 수 있기 때문에, api의 수가 많아질 수록 api를 관리하기 편하다는 장점이 있다고 한다.


이제 진짜 적용을 해보자.

적용을 해보기 전에 공식 문서를 간단하게 읽어보았다.

OpenAPI 3 Library for spring-boot

대략 정리를 해보자면 이런 기능을 지원해준다고 한다.

  • swagger-api 의 어노테이션을 사용하여 자동으로 JSON/YAML 및 HTML 형식으로 API 문서를 생성
  • 스프링 부트 (v1,v2,v3) 에 대한 지원
  • JSR-303 빈 검증(bean validation) 기능 지원 [@NotNull, @Min, @Max, @Size 등]
  • Swagger-ui
  • OAuth2

의존성 추가

implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'

YML 설정 추가

OpenAPI 3 Library for spring-boot

를 확인하여 yml 설정을 추가 해보자.

springdoc:
  api-docs:
    enabled: true 
    version: openapi_3_0 #사용하는 버전을 명시
    packagesToScan: mokindang.jubging #api-docs 의 스캔 범위를 지정
    path: /v3/api-docs #api 문서 확인 경로, localhost:8080/v3/api-docs 로 접근

  default-consumes-media-type: application/json #기본으로 설정되는 미디어타입 지정
  auto-tag-classes: true #오토 태그 기능 활성화
  groups:
    enabled: false #api 그룹 기능, default는 true 이나 당장 사용하지 않기에 false 로 지정

  swagger-ui:
    operationsSorter: method #method 기준으로 정렬, 그외 alpha 로 정렬 가능
    path: /swagger-ui.html #swagger ui 의 api 문서 확인 경로 defalut 는 /swagger-ui.html 이다.

사실 대부분 디폴트로 지정되는 값들을 그대로 사용하였고, 커스터마이징 한 부분은 swagger-ui.operationsSorterspringdoc.api-docs.groups 부분이다.

그룹화 기능은 아직 필요성을 못 느끼기에 현재 사용하지 않을 것으로 판단되어 적용하지 않았다.

또한 메서드를 기반으로 정렬하는 것이 api 문서의 가독성이 좋을 것이라 생각하여 메서드로 정렬하였다.

추가적으로 default-consumes-media-type: application/json 설정은 현재 프로젝트에서 json 형태의 api 방식으로 개발을 진행하기에 application/json 설정을 디폴트로 두었다.


Configuration 설정

OpenAPI 와 관련된 Configuration 설정을 해주어야 한다.

일반적으로 http://localhost:8080/swagger-ui.html 에 접속하면 다음과 같이 swagger-ui 를 확인할 수 있다.

이 화면은 정말 아무것도 설정되어 있지 않은 default 화면이다. 즉 해당 api 문서가 어떤 것에 대한 것인지 설명이 없다.

따라서 이런 설정을 해줘야한다. 그래서 OpenAPI 설정을 해줘야한다.

Configuration 설정 - OpenAPI

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI openAPI() {
        Info info = new Info()
                .version("v1.0.0")
                .title("API - 우리동네줍깅")
                .description("API Description");

        return new OpenAPI()
                .info(info);
    }
}

상단과 같이 설정을 하게 되면 다음과 같이 swagger-ui 가 바뀌게 된다.


Open API Docs 생성해보기

예제1 - 간단하게 생성해보기

package mokindang.jubging.project_backend.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "테스트용")
@RestController
public class TestController {

    @Operation(summary = "이름을 조회.") // 정의하려는 API 명시
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "이름 조회"),
            @ApiResponse(responseCode = "400", description = "존재하지 않는 이름 조회")
    })
    @GetMapping("/api/test/name")
    public ResponseEntity<String> name() {
        return ResponseEntity.ok()
                .body("홍길동");
    }
}

예제 2 - RequestDto 와 Controller 에 대한 스웨거 어노테이션 적용

우선 응답값에 대한 어노테이션을 적용 해보자.

@Tag → 같은 name 으로 묶어둔 api 를 swagger-ui 에서 확인 할 수 있다. 말 그대로 태그 기능

@Operation → 메서드를 OpenApi 작업으로 정의하고, 해당 api 요청에 대한 정의를 함.

@ApiResponse() → Api 요청시 반환되는 값에 대한 매핑을 할 수 있다.

@Slf4j
@Tag(name = "게시판", description = "게시판 관련 api")
@RequestMapping("/api/boards")
@RestController
@RequiredArgsConstructor
public class BoardController {

    private final BoardService boardService;

    @Operation(summary = "새글작성")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "새글작성"),
            @ApiResponse(responseCode = "400", description = "유효하지 않은 유저"),
            @ApiResponse(responseCode = "400", description = "유효하지 않은 본문내용"),
            @ApiResponse(responseCode = "400", description = "유효하지 않은 제목")
    })
    @PostMapping
    public ResponseEntity<Void> write(@Login Long memberId, @RequestBody final BoardCreateRequest boardCreateRequest) {
        log.info("memberId = {} 의 새글작성", memberId);
        boardService.write(memberId, boardCreateRequest);
        return ResponseEntity.status(HttpStatus.CREATED)
                .build();
    }
}

다음과 같이 새글작성 api 요청의 응답에 대한 명세를 확인 할 수 있다.

BoardCreateRequest

@Schema → api 요청 시 매핑된 필드에 대한 명세를 할 수 있다.

@Schema(description = "BoardCreateRequest")
@Getter
@RequiredArgsConstructor
public class BoardCreateRequest {

    @NotNull
    @Schema(description = "게시글 제목", example = "예시 제목 입니다.")
    private final String title;

    @NotNull
    @Schema(description = "게시글 본문", example = "예시 본문 입니다.")
    private final String content;

    @NotNull
    @Schema(description = "활동 종류", example = "달리기", allowableValues = {"달리기", "산책"})
    private final String activityCategory;

    @NotNull
    @Schema(description = "활동 시작일", example = "2023-11-23", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private final LocalDate startDate;
}

다음과 같이 새글작성 api 요청 의 RequestBody 에 대한 api 명세를 확인 할 수 있다.

그외 출처: https://velog.io/@byeongju/Swaggerfeat.-Springdoc-OpenAPI-dccyrdig

0개의 댓글