java에서는 타입 안전 열거형 패턴 을 편리하게 사용할 수 있도록 열거형(enum) 타입을 제공
열거형을 사용하는 이점
문자열 타입 안전성( 컴파일 시 오류 감지 )
외부에서 임의로 생성 불
직접 구현
public class Grade extends Enum {
// 문자열로 직접 사용하지 않도록 객체 생성
public static final Grade BASIC = new Grade(10, "베이직");
public static final Grade GOLD = new Grade(20, "골드");
public static final Grade DIAMOND = new Grade(30, "다이아몬드");
// enum 종류에 따라 변하는 값이므로 안에서 선언
private final int discountPercent;
private final String description;
// 외부에서 생성되지 않도록
private Grade(int discountPercent, String description){
this.discountPercent = discountPercent;
this.description = description;
}
public int discount(int price){
return price * discountPercent / 100;
}
}
enum으로 변경
class enum Grade{
BASIC(10, "베이직"),
GOLD(20, "골드"),
DIAMOND(30, "다이아몬드");
private final int discountPercent;
private final String description;
Grade(int discountPercent, String description){
this.discountPercent = discountPercent;
this.description = description;
}
public int discount(int price){
return price * discountPercent / 100 ;
}
}
Springdoc-openapi는 java 라이브러리이고 Spring Boot 프로젝트를 사용하여 API 문서 생성을 자동화해준다.
Spring Boot2 이하는 Springdoc-openapi v1.8.0까지만 지원된다.
Springdoc-openapi는 런타임에 애플리케이션을 검사할 때 작동한다.
자동으로 JSON / YAML 그리고 HTML 포맷으로 API들을 문서로 생성한다. (-> Swagger가 공홈에서 왜 yaml파일로 작성되어있는지 알게 되었다.)
이 라이브러리는 - openAPI 3 - Spring Boot 3 - JSR-303 (특히, @NotNull, @Min, @Max, @Size) - Swagger-UI - OAuth2 - GraalVM native images 를 지원한다.
Swagger 제품 중 Swagger UI를 사용 ( -> 기본 포맷을 작성하지 않는 것으로 보아 UI툴을 사용한다는 예상이 맞았던 것 같다.)
Springdoc-openapi 적용하기
build.gradle에
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.7.0'
# 혹은
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
# 을 추가한다. ( 작성 당시 최신 안정화 파일이 2.7.0 버전이다. )
Swgagger UI 페이지는 'http://server:port/context-path/swagger-ui.html'에서 이용 가능
'http://server:port/context-path/v3/api-docs'에서 json 파일을 생성 가능
'http://server:port/context-path/v3/api-docs.yaml'에서 yaml파일을 생성 가능
코드에 추가하기
@Tag(name = "User", description = "User API") // Controller 단위로 관리
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// @Operation를 이용해 해당 API가 어떤 리소스를 나타내는지 간략한 설명을 추가할 수 있다.
@Operation(summary = "Get user", description = "특정 유저의 상세 정보를 조회한다.")
// @ApiResponses를 이용해 해당 API의 Response 정보들을 나타낼 수 있다.
@ApiResponses(value = {
// @ApiResponse는 단일 Response에 대한 정보를 나타낸다.
@ApiResponse(responseCode = "200", description = "성공",
// content는 response의 데이터 포맷을 알려준다
content = {@Content(schema = @Schema(implementation = UserRes.class))}),
// 만약 데이터 타입이 List인 경우
// {@Content(mediaType = "application/json",
// array = @ArraySchema(schema = @Schema(implementation = UserRes.class)))}
@ApiResponse(responseCode = "404", description = "해당 ID의 유저가 존재하지 않습니다."),
})
@GetMapping("/{userId}")
public UserRes getUser(
// @Schema와 @Parameter로 설명 가능하다.
@Positive(message = "유저 ID는 양수입니다.")
@Schema(description = "User ID", example = "1")
@PathVariable Long userId,
@Positive(message = "유저 ID는 양수입니다.")
@Parameter(name = "loginId", description = "로그인 유저 ID 값",
example = "3", required = true)
@RequestParam final Long loginId
//, @RequestBody @Valid UserUpdateReq request
) {
return userService.getUser(userId, loginId);
}
}
RequestDTO와 responseDTO에 대한 명세
// @Schema로 클래스와 필드를 설명할 수 있다.
@Schema(description = "User response")
@Getter
@AllArgsConstructor
public class UserRes {
@NotBlank(message = "사용자 이름을 입력해주세요.")
@Length(max = 20, message = "사용자 이름은 20글자 이하로 입력해야 합니다.")
@Schema(description = "user name", example = "Kim")
private String name;
@NotBlank(message = "사용자 닉네임을 입력해주세요.")
@Length(max = 20, message = "사용자 닉네임은 20글자 이하로 입력해야 합니다.")
@Schema(description = "user nickname", example = "kim")
private String nickname;
}