Swagger 작성 가이드 : 예시와 함께 이해하는 API Swagger 작성 방법
0. swagger 확인할 수 있는 url 경로
- 로컬 경로 뒤에
/swagger-ui/index.html
를 붙여준다.
<Example>
http://localhost:5100/swagger-ui/index.html
1. Controller
<POST Example>
@Operation(summary = "회원가입", method = "POST", description = "사용자가 회원가입을 한다.")
@ResponseStatus(code = HttpStatus.OK)
@ApiResponseWithErrorCode({
@ResponseDataAnnotation(
statusCode = INVALID_INPUT_DATA,
description = "입력한 데이터가 유효하지 않을 경우"),
@ResponseDataAnnotation(
statusCode = DUPLICATED,
description = "중복된 데이터로 회원가입 요청을 했을 경우")
})
@PostMapping(path = "/user/signUp")
@ResponseBody
public ResponseEntity<ResponseData<Void>> signUp(
@RequestBody @Valid SignUpRequestDTO signUpRequestDTO) throws Exception {
userService.signUp(signUpRequestDTO);
return ResponseUtility.createPostSyncSuccessResponse();
}
<GET Example>
@Operation(
summary = "get user list",
method = "GET",
description = "검색어를 받아 유저 리스트를 페이지 단위로 조회하고 반환한다.",
parameters = {
@Parameter(name = "userName"),
@Parameter(name = "userGrade", description = "user의 등급 ex)VIP, PREMIUM"),
@Parameter(name = "page", description = "page number ex)1"),
@Parameter(name = "size", description = "paging size ex)10"),
@Parameter(name = "sort", description = "sort ex)lastUpdateDatetime,desc"),
})
@GetMapping(path = "/user/users")
@ResponseBody
public ResponseEntity<ResponsePagingData<UserListResponseDTO>> retrieveUserList(
@RequestParam(required = false) String userName,
@RequestParam(required = false) String userGrade,
@RequestParam(required = false, defaultValue = "1") Integer page,
@RequestParam(required = false, defaultValue = "10") Integer size,
@RequestParam(required = false, defaultValue = "lastUpdateDatetime,desc") String sort) {
Pageable pageRequest = CustomPageRequest.of(page, size, sort);
return ResponseUtility.createSuccessPagingResponse(
userService.retrieveUserList(
userName, userGrade, pageRequest));
}
1.1 @Operation
@Operation(
summary = "get user list",
method = "GET",
description = "검색어를 받아 유저 리스트를 페이지 단위로 조회하고 반환한다.",
parameters = {
@Parameter(name = "userName"),
@Parameter(name = "userGrade", description = "user의 등급 ex)VIP, PREMIUM"),
@Parameter(name = "page", description = "page number ex)1"),
@Parameter(name = "size", description = "paging size ex)10"),
@Parameter(name = "sort", description = "sort ex)lastUpdateDatetime,desc"),
})
1.2 @ApiResponse
@ApiResponse(responseCode = "201", description = "CREATED")
- responseCode 가 200이 아닌 경우 아래 코드 추가 필요
@ResponseStatus(code = HttpStatus.CREATED)
- custom annotation for error code format. (에러 케이스 표현에 사용. 메소드 내에서 발생 가능한 모든 에러 케이스를 작성할 것.)
@ApiResponseWithErrorCode({
@ResponseDataAnnotation(
statusCode = INVALID_INPUT_DATA,
description = "입력한 데이터가 유효하지 않을 경우"),
@ResponseDataAnnotation(
statusCode = DUPLICATED,
description = "중복된 데이터로 회원가입 요청을 했을 경우")
})
- response의 schema를 직접 정의 가능 (꼭 필요한 경우에만 사용 권장. 기본은 컨트롤러 함수에 리턴 타입 명시.)
@ApiResponse(
responseCode = "201",
description = "CREATED",
content =
@Content(
mediaType = "application/json",
schema =
@Schema(
implementation =
IdSignInResponseDTO.class)))
1.3 @Parameter
생략...
parameters = {
@Parameter(name = "userName"),
@Parameter(name = "userGrade", description = "user의 등급 ex)VIP, PREMIUM"),
@Parameter(name = "page", description = "page number ex)1"),
@Parameter(name = "size", description = "paging size ex)10"),
@Parameter(name = "sort", description = "sort ex)lastUpdateDatetime,desc"),
})
...중략...
public ResponseEntity<ResponsePagingData<UserListResponseDTO>> retrieveUserList(
@RequestParam(required = false) String userName,
@RequestParam(required = false) String userGrade,
@RequestParam(required = false, defaultValue = "1") Integer page,
@RequestParam(required = false, defaultValue = "10") Integer size,
@RequestParam(required = false, defaultValue = "lastUpdateDatetime,desc") String sort) {
...생략
- RequestParam과 함께 정의하여 사용. (기본 1:1 매핑, description 등 필요 없으면 생략 가능)
- Parameter는 @Operation 내에 정의하도록 함.
- x-correlation-id, x-language-code는 모두 공통이므로 @Parameter 입력하지 않음
- 컨트롤러 함수의 리턴 값을 명시하여 swagger 상 표현되도록 함.
- 이름만으로 용도를 알기 어려운 데이터는 description 상에 용도를 표현
- 필수 파라미터 여부를
required
로 명시할 것.
1.4 @io.swagger.v3.oas.annotations.parameters.RequestBody
public ResponseEntity<ResponseData<CollectionRequestResponseDTO>> updateCollection(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
content =
@Content(
schema =
@Schema(
implementation =
CollectionRequestResponseDTO
.class)))
@RequestBody
HashMap<String, Object> changes,
@PathVariable("collectionId") Integer collectionId)
Map의 사용은 지양하되, 부득이 사용하는 경우 @RequestBody를 직접 명시하여 swagger 상 표현되도록 함.
2. DTO
package io.naemo.centralwallet.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GoogleOTPKeyResponseDTO {
@Schema(
name = "googleOtpKey",
description = "32자의 google OTP secret key.",
example = "QGXKNGCQ3L36PTMFQQP5SHW3MYDEPS3J")
private String googleOtpKey;
@Schema(
name = "googleOtpQRCodeUrl",
description = "google OTP secret key의 QR 코드 주소. FE에서 QR코드 이미지로 변환해서 노출됨.",
example =
"otpauth://totp/NAEMO%3Amp_member01%40gmail.com?secret=QGXKNGCQ3L36PTMFQQP5SHW3MYDEPS3J&issuer=NAEMO")
private String googleOtpQRCodeUrl;
@Builder
public GoogleOTPKeyResponseDTO(String googleOtpKey, String googleOtpQRCodeUrl) {
this.googleOtpKey = googleOtpKey;
this.googleOtpQRCodeUrl = googoleOtpQRCodeUrl;
}
}
- API의 request, response class
@NotBlank, @NotNull, @Positive
와 같은 @Valid는 request에서 사용.- 위와 같은
@Valid
가 사용되었다면MANDATORY_PARAM_ERR
와 같은@ApiResponseWithErrorCode
챙길 것. - 서로 다른 API에서 DTO를 공통으로 사용할 수 없다면 분리.
- 코드성 데이터는 enum 타입으로 정의 혹은 description 상에 표현( ex. “N_ETHEREUM/N_SOLANA”)
- 이름만으로 용도를 알기 어려운 데이터는 description 상에 용도를 표현
2.1 @Schema
@Schema(
name = "googleOtpKey",
description = "32자의 google OTP secret key.",
example = "QGXKNGCQ3L36PTMFQQP5SHW3MYDEPS3J")
3. 작성시 주의 사항
- INVALID_MEBER_INFORMATION → 공통 description으로
Member information is not founded by session.
사용- 사용 예시
@ApiResponseWithErrorCode({
@ResponseDataAnnotation(
statusCode = INVALID_MEMBER_INFORMATION,
description = "Session에서 사용자 정보를 가져오지 못했을 경우")
})
-
모든 예시 적어주기 - YN, true/false 포함 (
...
과 같은 축약어 사용하지 말 것.)-
사용예시
```java @Schema(name = "useYn", description = "해당 2FA 사용여부 ex) Y/N", example = "Y") @NotEmpty@Setterprivate String useYn; ```
-
description 상에 예시 작성
-
-
input data 관련 에러 리턴인 경우, input의 이름과 맞춰주기
- ex) input으로 들어온 actionType에 대한 에러 처리 →
INVALID_TRANSACTION
가 아니라INVALID_ACTION_TYPE
으로 수정 - 필요시 연관 로직/모듈테스트 함께 수정
- ex) input으로 들어온 actionType에 대한 에러 처리 →
-
공통의 DTO를 사용하게 되면서 사용하지 않는 파라미터들의 불필요한 노출
- 필요하다면 DTO 분리
- 노출되지 않아도 된다면 @Schema(hidden = true)
- 사용하지 않는 파라미터는 제거
- enum 타입으로 선언하여 불필요한 코드값이 같이 노출되는 경우, description으로 사용 가능한 코드값 명시
-
이름만으로 용도 확인이 가능하다면 추가 description을 달지 않아도 됨
- 이름만으로 알 수 없다면 자세한 description 추가
- 코드성의 데이터는 enum 사용 혹은 description/example 등에 모든 값 명시
- paging의 sort도 가능한 정렬 조건 모두 표기
-
API에서 핸들링하는 exception 모두 표기
- 필요한 경우 exception 내용 변경 또는 구체화
참고) OpenAPI Specification - Version 3.0.3 | Swagger OpenAPI 3 Library for spring-boot (springdoc.org)
댓글남기기