{
"isSuccess ": true,
"code" : "2000",
"message" : "OK",
"result" :
{
"testString" : "This is test!"
}
}
위 처럼 응답을 통일해야 프론트측에서 편하게 사용가능하다
먼저 위 json의 형식을 맞추어줄 클래스를 만든다.
@Getter
@AllArgsConstructor
@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
public class
ApiResponse<T> {
@JsonProperty("isSuccess")
private final Boolean isSuccess;
private final String code;
private final String message;
@JsonInclude(JsonInclude.Include.NON_NULL)
private final T result;
// 일반적인 응답 생성
public static <T> ApiResponse<T> onSuccess(T result){
return new ApiResponse<>(true, SuccessStatus._OK.getCode() , SuccessStatus._OK.getMessage(), result);
}
public static <T> ApiResponse<T> of(BaseCode code, T result){
return new ApiResponse<>(true, code.getReasonHttpStatus().getCode() , code.getReasonHttpStatus().getMessage(), result);
}
// 실패한 경우 응답 생성
public static <T> ApiResponse<T> onFailure(String code, String message, T data) {
return new ApiResponse<>(false, code, message, data);
}
}
위에서 메서드를 제외하면 응답되는것(필드) 간단하다. (당장 빨간불이 있다면 주석!)
위에서 명시한 메서드중 onSuccess
를 가장 많이 사용하지만 onFailure
같은 메서드는 에러 핸들링을 위해 사용된다.
private final Boolean isSuccess;
private final String code;
private final String message;
private final T result;
{
"isSuccess ": true,
"code" : "2000",
"message" : "OK",
"result" :
{
"testString" : "This is test!"
}
}
이렇게 4개이다.
위에서 Message와 Code 필드는 일관성이 있어야 하기에 다른 클래스로 관리한다.
Status들은 열거형이다
public interface BaseCode {
public ReasonDTO getReason();
public ReasonDTO getReasonHttpStatus();
}
public interface BaseErrorCode {
public ErrorReasonDTO getReason();
public ErrorReasonDTO getReasonHttpStatus();
}
위 두가지 인터페이스 모두 getReason() 과 getReasonHttpStatus() 메서드를 가지고 있으며
새로운 응답 코드를 만들때 위 인터페이스를 상속시켜 구현을 강제 한다!!
public class ReasonDTO {
private String code;
private String message;
private Boolean isSuccess;
private HttpStatus httpStatus;
}
---
public class ErrorReasonDTO {
private String code;
private String message;
private HttpStatus httpStatus;
private Boolean isSuccess;
}
그러면 이제 가장 많이 쓰일 SuccessStatus
를 만들어보자
성공코드이기 때문에 BaseCode를 구현한다. (실패코드면 BaseErrorCode)
@Getter
@AllArgsConstructor
public enum SuccessStatus implements BaseCode {
// enum중 하나 _OK 이라는 이넘값
_OK(HttpStatus.OK, "2000", "Ok"),;
// 이넘 값도 필드를 가질수 있으며 롬복에 의해 생성자로 주입된다.
//HttpStatus는 Spring에 내장되어있는 클래스로 우리가 그냥 에러 뱉을때 사용하는 클래스이다.
private HttpStatus httpStatus;
//code는 우리가 일관성 있게 만들어 줘야 한다.
private String code;
//message를 이용해 상태를 알려줄수 있다.
private String message;
@Override
public ReasonDTO getReason() {
return ReasonDTO.builder()
.code(message)
.message(code)
.isSuccess(true)
.build();
}
@Override
public ReasonDTO getReasonHttpStatus() {
return ReasonDTO.builder()
.code(message)
.message(code)
.isSuccess(true)
.httpStatus(httpStatus)
.build();
}
}
@Getter
@AllArgsConstructor
public enum ErrorStatus implements BaseErrorCode {
// 가장 일반적인 응답
_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 에러, 관리자에게 문의 바랍니다."),
_BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON400","잘못된 요청입니다."),
_UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON401","인증이 필요합니다."),
_FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."),
...
;
private HttpStatus httpStatus;
private String code;
private String message;
@Override
public ErrorReasonDTO getReason() {
return ErrorReasonDTO.builder()
.code(message)
.message(code)
.isSuccess(false)
.build();
}
@Override
public ErrorReasonDTO getReasonHttpStatus() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build()
;
}
}
우리는 이제 API응답을 통일이 가능하다.
TempRestController
@RestController
@RequiredArgsConstructor
@RequestMapping("/temp")
public class TempRestController {
private final TempQueryService tempQueryService;
@GetMapping("/test")
public ApiResponse<TempResponse.TempTestDTO> testAPI() {
return ApiResponse.onSuccess(TempConverter.toTempTestDTO());
}
}