3월에 시작한 프로젝트부터 공통 response를 구현해 사용했고 마침 새로운 프로젝트를 진행하면서 조금 변형하는 김에 티스토리에 정리하고자 한다. 사실 이전까지는 프론트에게 response를 넘겨줄 때 포멧을 생각하지 않았다. 그냥 응답 data가 잘 보내지면 그것에 만족하는 삶을 살았는데 생각해보니 data 말고도 넘겨주면 좋은 것들이 있었고, 특정 포멧으로 모든 response를 보내면 더 통일감이 있을 것 같았다.
Json 포멧
성공과 실패 상황일 경우에 상태를 알려주는 status, response code 값, message, data, timestamp를 항상 같은 형식으로 보내주게끔 했다. 사실 이전 프로젝트에서는 code 값을 httpStatus code로 사용했는데 성공과 실패일 경우에는 항상 status code가 200이라서 의미가 없는 것 같고, 자체적인 코드 값을 사용해 보고 싶어서 만들어서 사용했다. error가 아닌 경우에도 timestamp를 보내줘야 할지는 잘 모르겠지만 있으면 언젠가는 사용할 수 있을 것 같아서 넣었다.
{
"status": "SUCCESS",
"code": "S001",
"message": "성공입니다",
"data": "data",
"timestamp": "2023-06-25T14:59:52.7088744"
}
실제 코드
ResponseStatus
public enum ResponseStatus {
SUCCESS, FAILURE
}
RepsonseCode
@Getter
@AllArgsConstructor
public enum ResponseCode {
SUCCESS("S001", "요청이 완료 되었습니다."),
CREATED("S002", "생성이 완료되었습니다."),
NO_CONTENT("S003", "요청에 대한 정보가 없습니다."),
FAILURE("F001", "에러는 아니지만 실패했습니다.");
private final String code;
private final String message;
}
Response
성공 시에는 detail message를 설정하는 경우와 code의 message를 사용하는 경우, 반환값이 없는 경우를 고려했다. 이때 반환되는 data가 없을 때에 null을 반환하도록 했는데 이렇게 구현하는 것이 좋은 건지는 잘 모르겠다.. ResponseEntity의 body 부분에 Response를 넣어 반환하도록 만들었는데 헤더를 붙이는 경우가 있을수도 있을 것 같아서 그렇게 구현했다.
@Getter
@NoArgsConstructor
public class Response<T> {
private ResponseStatus status;
private String code;
private String message;
private T data;
private LocalDateTime timestamp;
@Builder
public Response(ResponseStatus status, String code, String message, T data) {
this.status = status;
this.code = code;
this.message = message;
this.data = data;
this.timestamp = LocalDateTime.now();
}
public static <T>ResponseEntity<Response> SUCCESS(ResponseCode code, T data){
return new ResponseEntity( Response.builder()
.status(ResponseStatus.SUCCESS)
.code(code.getCode())
.message(code.getMessage())
.data(data)
.build(), HttpStatus.OK);
}
public static <T>ResponseEntity<Response> SUCCESS(ResponseCode code, String message, T data){
return new ResponseEntity( Response.builder()
.status(ResponseStatus.SUCCESS)
.code(code.getCode())
.message(message)
.data(data)
.build(), HttpStatus.OK);
}
public static <T>ResponseEntity<Response> SUCCESS(){
return new ResponseEntity( Response.builder()
.status(ResponseStatus.SUCCESS)
.code("S001")
.message("ok")
.data(null)
.build(), HttpStatus.OK);
}
public static <T>ResponseEntity<Response> FAILURE(ResponseCode code){
return new ResponseEntity( Response.builder()
.status(ResponseStatus.FAILURE)
.code(code.getCode())
.message(code.getMessage())
.data(null)
.build(), HttpStatus.OK);
}
public static <T>ResponseEntity<Response> FAILURE(ResponseCode code, String message){
return new ResponseEntity( Response.builder()
.status(ResponseStatus.FAILURE)
.code(code.getCode())
.message(message)
.data(null)
.build(), HttpStatus.OK);
}
}