-
Spring boot 2.7.18에서 swagger 설정하기 <2>프레임워크/Spring Boot 2024. 1. 23. 02:21프로젝트를 함께 만들고 있는 프론트엔드 개발자들과 효율적인 커뮤니케이션을 위해서 스웨거를 사용하려고 합니다.적용하면 만난 이런 저런 이슈 사항들을 기록해보았습니다.
프로젝트 버전
spring boot: 2.7.18
springdoc-openapi-ui: 1.7.0
1. 프로젝트 코드에 작성
어노테이션을 사용해서 컨트롤러의 메소드와 관련된 dto들에 명세를 추가해주면 web에서 확인이 가능합니다.
- api 명세 작성
@Operation(summary = "게시글 생성", description = "제목, 내용, 작성자, 카테고리를 포함하는 게시글을 작성합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "게시물 생성 성공하였습니다."), @ApiResponse(responseCode = "400", description = "잘못된 요청입니다. 입력 데이터를 확인하세요."), @ApiResponse(responseCode = "500", description = "서버 내부 오류가 발생했습니다.") }) @ResponseStatus(HttpStatus.CREATED) @PostMapping("/post") public void createPost(@Valid @RequestBody CreateReqDto dto) { postService.createPost(dto); }
- 요청 dto 의 스키마 작성
@Getter @ToString @RequiredArgsConstructor public class CreateReqDto { @Schema(description = "게시글의 제목", example = "Why this error occurs?") @NotBlank(message = "제목은 필수 입력 값입니다.") private final String title; @Schema(description = "게시글의 내용", example = "When I start my server, the error below shows") @NotBlank(message = "내용은 필수 입력 값입니다.") private final String content; @Schema(description = "게시글의 카테고리", example = "질문, 홍보, 상담") @NotNull(message = "카테고리는 필수 입력 값입니다.") private final String category; @Schema(description = "게시글의 작성자", example = "jack") @NotNull(message = "작성자는 필수 입력 값입니다.") private final String creator; }
- 에러 dto의 스키마 작성
@Schema(description = "에러 응답") @Getter public class HttpErrorInfo { @Schema(description = "에러 발생 시간", example = "2023-01-01T12:00:00") private final LocalDateTime timestamp; @Schema(description = "에러 발생 경로", example = "/api/v1/post") private final String path; @Schema(description = "HTTP 상태 코드", example = "400, 500") private final HttpStatus httpStatus; @Schema(description = "에러 메세지", example = "잘못된 입력입니다. 입력값을 확인해주세요") private final String message; public HttpErrorInfo(HttpStatus httpStatus, String path, String message) { timestamp = LocalDateTime.now(); this.httpStatus = httpStatus; this.path = path; this.message = message; } }
- application.yml에 media-type 추가
springdoc: default-produces-media-type: application/json default-consumes-media-type: application/json
모두 작성해주고 서버를 다시 실행하면 Swagger-ui 화면에서 반영된 내용을 확인할 수 있다.
에러 dto 같은 경우 Controller에서 직접 'content' 프로퍼티로 추가하지 않아도 자동으로 맵핑이 됩니다.
하지만 Controller의 모든 메소드에 성공, 실패 케이스를 꼼꼼하게 작성하다보면 컨트롤러 로직보다 api 명세 관련 코드가 더 많아질 것이고 유지보수에 어려움이 생길 것 같은 느낌이 강하게 듭니다.
2. 인터페이스를 사용
명세를 인터페이스로 분리하여 관리하는 것도 하나의 방법이 될 수 있다고 생각합니다.
최소한 로직과 명세를 분리하여 작업자가 하나의 관심사만 신경쓸 수 있게 됩니다.
- 인터페이스에 명세 작성
public interface PostController { @Operation(summary = "게시글 생성", description = "제목, 내용, 작성자, 카테고리를 포함하는 게시글을 작성합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "게시물 생성 성공하였습니다."), @ApiResponse(responseCode = "400", description = "잘못된 요청입니다. 입력 데이터를 확인하세요."), @ApiResponse(responseCode = "500", description = "서버 내부 오류가 발생했습니다.") }) @ResponseStatus(HttpStatus.CREATED) @PostMapping("/post") void createPost(@Valid @RequestBody CreateReqDto dto); @GetMapping("/post") ListReqDto<Post> getPostList( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size ); }
- 컨트롤러에 로직 작성
@Slf4j @RequiredArgsConstructor @RestController @RequestMapping("/api/v1") public class PostControllerImpl implements PostController { private final PostService postService; @Override public void createPost(@Valid @RequestBody CreateReqDto dto) { postService.createPost(dto); } @Override public ListReqDto<Post> getPostList( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size ) { Pageable pageable = PageRequest.of(page - 1, size); ListReqDto<Post> dto = postService.getPostList(pageable); return dto; } }
파일이 분리된 만큼 로직을 변경하면서 명세 갱신은 누락되는 경우가 발생할 수도 있겠으나 저는 개인적으로 나눠쓰는 것도 나쁘지 않다고 생각이 됩니다.
[글 대표 이미지 출처]
'프레임워크 > Spring Boot' 카테고리의 다른 글
데이터베이스를 기반으로 JPA의 연관관계 살펴보기 <1> (0) 2024.02.06 Entity의 Id 생성 전략에 따른 EntityManager의 persist 동작 확인 (0) 2024.02.06 Spring boot 2.7.18에서 swagger 설정하기 <1> (0) 2024.01.22 mongodb의 @Indexed 가 작동하지 않을 때 (0) 2023.12.24 Junit5 에서 Junit4로 변경하기 (0) 2023.12.24