일친 (IlChin) - 리스폰스 DTO 생성

no.oneho·2025년 5월 29일
0

일친 개발기

목록 보기
4/17
post-thumbnail

현재 프로젝트는 sql 관련 세팅 (repo, querydsl 세팅등) 정도로 해두었다.
이번 포스팅에는 모든 리스폰스를 처리하는 dto를 통해 일관된 구조로 응답을 내려보도록 하겠다.

먼저 내가 원하는 형식의 dto를 하나 생성한다
/dto/Response.class

@Getter
@NoArgsConstructor
@Builder
public class Response<T> {

    private String message;
    private HttpStatus code;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private T data;

    @Builder
    public Response(String message, HttpStatus code, T data) {
        this.message = message;
        this.code = code;
        this.data = data;
    }

}

첫번째 String 의 경우 응답 결과에 따른 메시지, 오류 메시지를 담는 공간
code는 HttpStatus code를 담는 공간

그리고 제일 중요한 data 변수가 응답으로 보내줄 핵심 데이터가 들어갈 공간이다.
이 경우 data 변수안에 리스트, 정수, 문자열, 튜플등 가지각색에 데이터가 들어갈 가능성이 있는 변수 공간이기에 제네릭 Type으로 지정해서 만들어줬다.

그럼 dto를 만들었으니 이 DTO를 반환시켜줄 클래스를 생성하러 가보자

/utils/Api.class

public class Api {
    public static <T> Response<T> success(HttpStatus code, String message, T data) {
        return new Response<>(message, code.value(), data);
    }

    public static <T> Response<T> success(Integer code, String message, T data) {
        return new Response<>(message, code, data);
    }

    public static <T> Response<T> error(Integer code, String message) {
        return new Response<>(message, code, null);
    }

    public static <T> Response<T> error(HttpStatus code, String message) {
        return new Response<>(message, code.value(), null);
    }

}

단순 반환 구조, code의 경우 편의성을 위해 오버로딩 메서드 하나정도 더 만들어뒀다.

이제 이렇게 만든 구조를 테스트 코드를 사용해 테스트해보자

테스트코드
@Test
  void 정상_반환_테스트_숫자() throws Exception {
      String message = "성공";
      Integer data = 1;
      Integer code = 200;

      Response<Integer> response = Api.success(code, message, data);
      assertNotNull(response);
      assertEquals(code, response.getCode());
      assertEquals(message, response.getMessage());
      assertEquals(data, response.getData());
  }

  @Test
  void 정상_반환_테스트_문자열() throws Exception {
      String message = "성공";
      String data = "데이터";
      Integer code = 200;

      Response<String> response = Api.success(code, message, data);
      assertNotNull(response);
      assertEquals(code, response.getCode());
      assertEquals(message, response.getMessage());
      assertEquals(data, response.getData());
  }

  @Test
  void 정상_반환_테스트_리스트() throws Exception {
      String message = "성공";
      List<Integer> data = List.of(1, 2, 3);
      Integer code = 200;

      Response<List<Integer>> response = Api.success(code, message, data);
      assertNotNull(response);
      assertEquals(code, response.getCode());
      assertEquals(message, response.getMessage());
      assertEquals(data, response.getData());
  }

  @Test
  void 정상_반환_테스트_HTTP_코드() throws Exception {
      String message = "성공";
      Integer data = 1;

      Response<Integer> response = Api.success(HttpStatus.OK, message, data);
      assertNotNull(response);
      assertEquals(HttpStatus.OK.value(), response.getCode());
      assertEquals(message, response.getMessage());
      assertEquals(data, response.getData());
  }



  @Test
  void 에러_반환_테스트() throws Exception {
      Integer code = 400;
      String message = "잘못된 요청";

      Response<Void> response = Api.error(code, message);

      assertNotNull(response);
      assertEquals(message, response.getMessage());
      assertEquals(code, response.getCode());
      assertNull(response.getData());
  }

  @Test
  public void 에러_반환_테스트_HTTP_코드() {
      String message = "서버 오류";
      Response<Void> response = Api.error(HttpStatus.INTERNAL_SERVER_ERROR, message);

      assertNotNull(response);
      assertEquals(message, response.getMessage());
      assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getCode()); // 검증
      assertNull(response.getData());
  }

테스트 결과도 잘 나오는걸 확인 할 수 있다.

새롭게 만든 클래스를 테스트해봤으니 이제 실제 컨트롤러에 적용해서 확인을 해보도록 하겠다.

/controller/HelloworldController.class

@RestController
@RequestMapping("/hello")
public class HelloWorldController {

  @GetMapping("")
  public Response<String> hello() {
      return Api.success(200, "성공 메시지", "Hello World");
  }

}

아주아주 간단한 컨트롤러이다. 호출해보면?

예상대로 반환값이랑 json 형태로 잘 넘어오는걸 확인할 수 있다!

다음은 에러처리를 위한 포스팅을 하겠다

profile
이렇게 짜면 요구사항이나 기획이 변경됐을 때 불편하지 않을까? 라는 생각부터 시작해 설계를 해나가는 개발자

0개의 댓글