기존에 진행하던 프로젝트와 다르게 졸업작품은 프론트앤드 개발자 1명, 백앤드 개발자 2명 총 3명의 협업을 해야한다.
본격적으로 프로젝트를 진행하기에 앞서서, 기본적으로 설정을 해야할 것들을 정하던 중, 프론트앤드 개발자 분이 swagger 나 restdocs 적용했으면 좋을 것 같다는 의견을 내주셨다.
사실 기존에 진행하던 프로젝트에서 스웨거를 적용해볼까? 라는 생각도 했었는데, 미루다보니 적용을 못했고, 솔직히 조금 귀찮았었다.
그래서 이번 졸업작품 프로젝트에서는 개발 초기 부터 Swagger 혹은 Restdocs 를 적용해보기로 하였다.
그래도 일단 이 기술들이 무엇인지 찾아보았고, 왜 적용해야하는지 다시 한번 고민해보면서 정리를 하였다.
간단하게 설명하자면 API 문서를 자동으로 만들어 주는 라이브러리다. 어노테이션을 통해 생성된 API를 문서내에서 parameter 조작을 통해서 바로 실행할 수 있다.
RESTfull 서비스의 문서화를 도와주는 도구이다. Spring 테스트로 생성된 자동 생성 문서를 통해 api를 실행한다.
각각의 장단점을 살펴보자면
장점
단점
장점
단점
테스트 코드 작성 시 문서화가 가능하기 때문에, 테스트 코드 관리를 지속적으로 해줘야함
(단점이라기엔 관점에 따라 애매할 수도 있습니다.)
Api call을 통한 인수테스트를 진행 하는 과정에서, Controller Layer Test 로 RestDocs 생성을 한다면 중복되는 테스트가 존재함
이유
swagger에 대해 추가적으로 더 알아보기 위해서
API Documentation & Design Tools for Teams | Swagger
공식 사이트에 들어가서 이것저것 찾아보았다.
지원해주는 기능으로는
가 있다고한다.
SpringBoot 환경에서 swagger 를 사용하기 위해서는 springfox-swagger 혹은 springdoc 를 사용해야한다고 한다.
이 둘에 대해 알아보기로 했다.
우선 https://mvnrepository.com/ 에 접속해 각각의 라이브러리에 대한 서칭을 조금 해보았다.
springfox 라이브러리는 2020년 7월 14일 기준으로 업데이트가 되지 않고있다.
반면에 Springdoc OpenApi 는 비교적 현재인 2022 년 10월 16일 까지 업데이트가 이루어져있다.
업데이트 시기만 봐도 SpringDoc OpenApi를 사용하는 것이 더 좋다는 결론이 나왔기 때문에, springDoc OpenApi를 사용하기로 했다.
그래도 차이점에 대해서 추가적으로 더 알아보았는데,
springDoc 은 springfox 가 2년동안 지원하지 않는 기간 동안 webflux 를 지원하도록 업데이트가 되었다고 한다.
Springdoc
는 @Tag 어노테이션을 통해서 중복되는 어노테이션들을 관리할 수 있다고한다.
또한 api간 정렬을 할 수 있기 때문에, api의 수가 많아질 수록 api를 관리하기 편하다는 장점이 있다고 한다.
적용을 해보기 전에 공식 문서를 간단하게 읽어보았다.
OpenAPI 3 Library for spring-boot
대략 정리를 해보자면 이런 기능을 지원해준다고 한다.
implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'
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.operationsSorter
와 springdoc.api-docs.groups
부분이다.
그룹화 기능은 아직 필요성을 못 느끼기에 현재 사용하지 않을 것으로 판단되어 적용하지 않았다.
또한 메서드를 기반으로 정렬하는 것이 api 문서의 가독성이 좋을 것이라 생각하여 메서드로 정렬하였다.
추가적으로 default-consumes-media-type: application/json
설정은 현재 프로젝트에서 json
형태의 api
방식으로 개발을 진행하기에 application/json
설정을 디폴트로 두었다.
OpenAPI 와 관련된 Configuration 설정을 해주어야 한다.
일반적으로 http://localhost:8080/swagger-ui.html 에 접속하면 다음과 같이 swagger-ui 를 확인할 수 있다.
이 화면은 정말 아무것도 설정되어 있지 않은 default 화면이다. 즉 해당 api 문서가 어떤 것에 대한 것인지 설명이 없다.
따라서 이런 설정을 해줘야한다. 그래서 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 가 바뀌게 된다.
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("홍길동");
}
}
우선 응답값에 대한 어노테이션을 적용 해보자.
@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 요청
의 응답에 대한 명세를 확인 할 수 있다.
@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