From beed75a9bf6e7c1f0bf9e46a1b136a491aea2d27 Mon Sep 17 00:00:00 2001 From: Hai Nguyen <2nguyen.work@gmail.com> Date: Tue, 15 Sep 2026 21:39:24 +0700 Subject: [PATCH] feat: add new generic response --- .../core/common/response/ApiError.java | 17 ------- .../core/common/response/ApiResponse.java | 28 ++++++++++++ .../core/common/response/ErrorResponse.java | 10 ----- .../core/common/response/PagedResponse.java | 16 +++++++ .../core/common/response/ApiResponseTest.java | 45 +++++++++++++++++++ 5 files changed, 89 insertions(+), 27 deletions(-) delete mode 100644 src/main/java/aplp/backend/core/common/response/ApiError.java create mode 100644 src/main/java/aplp/backend/core/common/response/ApiResponse.java delete mode 100644 src/main/java/aplp/backend/core/common/response/ErrorResponse.java create mode 100644 src/main/java/aplp/backend/core/common/response/PagedResponse.java create mode 100644 src/test/java/aplp/backend/core/common/response/ApiResponseTest.java diff --git a/src/main/java/aplp/backend/core/common/response/ApiError.java b/src/main/java/aplp/backend/core/common/response/ApiError.java deleted file mode 100644 index b075558..0000000 --- a/src/main/java/aplp/backend/core/common/response/ApiError.java +++ /dev/null @@ -1,17 +0,0 @@ -package aplp.backend.core.common.response; - -import java.time.Instant; - -public record ApiError( - Instant timestamp, - int status, - String error, - String code, - String message, - String traceId -) { - - public static ApiError of(int status, String error, String code, String message, String traceId) { - return new ApiError(Instant.now(), status, error, code, message, traceId); - } -} \ No newline at end of file diff --git a/src/main/java/aplp/backend/core/common/response/ApiResponse.java b/src/main/java/aplp/backend/core/common/response/ApiResponse.java new file mode 100644 index 0000000..d2fb332 --- /dev/null +++ b/src/main/java/aplp/backend/core/common/response/ApiResponse.java @@ -0,0 +1,28 @@ +package aplp.backend.core.common.response; + +import java.time.Instant; + +public record ApiResponse( + boolean success, + String code, + String message, + T data, + Instant timestamp, + String traceId +) { + public static ApiResponse ok(T data) { + return new ApiResponse<>(true, "OK", "Success", data, Instant.now(), null); + } + + public static ApiResponse ok(String message, T data) { + return new ApiResponse<>(true, "OK", message, data, Instant.now(), null); + } + + public static ApiResponse error(String code, String message) { + return new ApiResponse<>(false, code, message, null, Instant.now(), null); + } + + public static ApiResponse error(String code, String message, String traceId) { + return new ApiResponse<>(false, code, message, null, Instant.now(), traceId); + } +} diff --git a/src/main/java/aplp/backend/core/common/response/ErrorResponse.java b/src/main/java/aplp/backend/core/common/response/ErrorResponse.java deleted file mode 100644 index 4e17dcb..0000000 --- a/src/main/java/aplp/backend/core/common/response/ErrorResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package aplp.backend.core.common.response; - -import java.time.LocalDateTime; - -public record ErrorResponse( - int status, - String message, - LocalDateTime timestamp -) { -} \ No newline at end of file diff --git a/src/main/java/aplp/backend/core/common/response/PagedResponse.java b/src/main/java/aplp/backend/core/common/response/PagedResponse.java new file mode 100644 index 0000000..4f0203d --- /dev/null +++ b/src/main/java/aplp/backend/core/common/response/PagedResponse.java @@ -0,0 +1,16 @@ +package aplp.backend.core.common.response; + +import java.util.List; + +public record PagedResponse( + List content, + int page, + int size, + long totalElements, + int totalPages +) { + public static PagedResponse of(List content, int page, int size, long totalElements) { + int totalPages = size <= 0 ? 0 : (int) Math.ceil((double) totalElements / size); + return new PagedResponse<>(content == null ? List.of() : List.copyOf(content), page, size, totalElements, totalPages); + } +} diff --git a/src/test/java/aplp/backend/core/common/response/ApiResponseTest.java b/src/test/java/aplp/backend/core/common/response/ApiResponseTest.java new file mode 100644 index 0000000..4815866 --- /dev/null +++ b/src/test/java/aplp/backend/core/common/response/ApiResponseTest.java @@ -0,0 +1,45 @@ +package aplp.backend.core.common.response; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ApiResponseTest { + + @Test + void ok_wrapsDataWithSuccessTrue() { + ApiResponse res = ApiResponse.ok("hello"); + + assertTrue(res.success()); + assertEquals("OK", res.code()); + assertNotNull(res.message()); + assertEquals("hello", res.data()); + assertNotNull(res.timestamp()); + assertNull(res.traceId()); + } + + @Test + void error_wrapsCodeWithoutData() { + ApiResponse res = ApiResponse.error("USER_NOT_FOUND", "User not found"); + + assertFalse(res.success()); + assertEquals("USER_NOT_FOUND", res.code()); + assertEquals("User not found", res.message()); + assertNull(res.data()); + assertNotNull(res.timestamp()); + } + + @Test + void pagedResponse_computesTotalPages() { + PagedResponse page = PagedResponse.of(List.of("a", "b"), 0, 10, 25); + + assertEquals(3, page.totalPages()); + assertEquals(2, page.content().size()); + + ApiResponse> res = ApiResponse.ok(page); + assertTrue(res.success()); + assertEquals(3, res.data().totalPages()); + } +}