Skip to content

Commit 0b2bdc4

Browse files
authored
[Feat/#323] 오늘의 코디 Preview와 Details 조회 API 구현 (#326)
* feat: 오늘의 코디 preview와 details api 구현 * refactor: spotless 적용
1 parent 6245a3a commit 0b2bdc4

8 files changed

Lines changed: 269 additions & 119 deletions

File tree

clokey-api/src/main/java/org/clokey/domain/coordinate/controller/CoordinateController.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,24 @@ public BaseResponse<SliceResponse<DailyCoordinateListResponse>> getDailyCoordina
101101
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
102102
}
103103

104-
@GetMapping("/daily/today")
104+
@GetMapping("/daily/today/preview")
105105
@Operation(
106-
operationId = "Coordinate_getTodayDailyCoordinateClothes",
107-
summary = "오늘의 코디 옷 정보 조회",
108-
description = "오늘의 코디에 포함된 옷 정보를 조회하는 API입니다.")
109-
public BaseResponse<List<DailyCoordinateClothResponse>> getTodayDailyCoordinateClothes() {
110-
List<DailyCoordinateClothResponse> response =
111-
coordinateService.getTodayDailyCoordinateClothes();
106+
operationId = "Coordinate_getTodayCoordinatePreview",
107+
summary = "오늘의 코디 Preview 조회",
108+
description = "오늘의 코디의 Preview를 조회하는 API입니다.")
109+
public BaseResponse<DailyCoordinatePreviewResponse> getTodayCoordinatePreview() {
110+
DailyCoordinatePreviewResponse response = coordinateService.getTodayCoordinatePreview();
111+
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
112+
}
113+
114+
@GetMapping("/daily/today/details")
115+
@Operation(
116+
operationId = "Coordinate_getTodayCoordinateDetails",
117+
summary = "오늘의 코디 Details 조회",
118+
description = "오늘의 코디의 Details를 조회하는 API입니다.")
119+
public BaseResponse<List<CoordinateDetailsListResponse>> getTodayCoordinateDetails() {
120+
List<CoordinateDetailsListResponse> response =
121+
coordinateService.getTodayCoordinateDetails();
112122
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
113123
}
114124

clokey-api/src/main/java/org/clokey/domain/coordinate/dto/response/DailyCoordinateClothResponse.java

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.clokey.domain.coordinate.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import java.time.LocalDate;
5+
import org.clokey.coordinate.entity.Coordinate;
6+
7+
public record DailyCoordinatePreviewResponse(
8+
@Schema(description = "오늘의 코디의 ID", example = "1") Long coordinateId,
9+
@Schema(description = "오늘의 코디의 imageUrl", example = "https://example.jpg") String imageUrl,
10+
@Schema(description = "오늘의 코디의 날짜", example = "2026-02-04") LocalDate date) {
11+
public static DailyCoordinatePreviewResponse from(Coordinate coordinate) {
12+
return new DailyCoordinatePreviewResponse(
13+
coordinate.getId(),
14+
coordinate.getImageUrl(),
15+
coordinate.getUpdatedAt().toLocalDate());
16+
}
17+
}

clokey-api/src/main/java/org/clokey/domain/coordinate/exception/CoordinateErrorCode.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ public enum CoordinateErrorCode implements BaseErrorCode {
1515
COORDINATE_NOT_IN_LOOK_BOOK(400, "COORDINATE_4005", "룩북에 속해있지 않은 (오늘의) 코디입니다."),
1616
COORDINATE_LIKE_LIMIT(400, "COORDINATE_4006", "최대 5개의 코디에 좋아요를 누를 수 있습니다."),
1717

18-
NOT_COORDINATE_OWNER(400, "COORDINATE_4031", "나의 코디가 아닙니다. 권한이 없습니다."),
18+
NOT_COORDINATE_OWNER(403, "COORDINATE_4031", "나의 코디가 아닙니다. 권한이 없습니다."),
1919

20-
COORDINATE_NOT_FOUND(400, "COORDINATE_4041", "존재하지 않는 코디입니다.");
20+
COORDINATE_NOT_FOUND(404, "COORDINATE_4041", "존재하지 않는 코디입니다."),
21+
DAILY_COORDINATE_NOT_FOUND(404, "COORDINATE_4042", "오늘의 코디가 존재하지 않습니다.");
2122

2223
private final int status;
2324
private final String code;

clokey-api/src/main/java/org/clokey/domain/coordinate/service/CoordinateService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ public interface CoordinateService {
2424
SliceResponse<DailyCoordinateListResponse> getDailyCoordinates(
2525
Long lastCoordinateId, int size, SortDirection direction);
2626

27-
List<DailyCoordinateClothResponse> getTodayDailyCoordinateClothes();
27+
DailyCoordinatePreviewResponse getTodayCoordinatePreview();
28+
29+
List<CoordinateDetailsListResponse> getTodayCoordinateDetails();
2830

2931
CoordinatePreviewResponse getCoordinatePreview(Long coordinateId);
3032

clokey-api/src/main/java/org/clokey/domain/coordinate/service/CoordinateServiceImpl.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -322,25 +322,19 @@ public SliceResponse<DailyCoordinateListResponse> getDailyCoordinates(
322322
}
323323

324324
@Override
325-
public List<DailyCoordinateClothResponse> getTodayDailyCoordinateClothes() {
325+
public DailyCoordinatePreviewResponse getTodayCoordinatePreview() {
326326
final Member currentMember = memberUtil.getCurrentMember();
327-
Optional<Coordinate> coordinate =
328-
coordinateRepository.findDailyCoordinateByDateAndMemberId(
329-
LocalDate.now(), currentMember.getId());
327+
final Coordinate coordinate = getTodayDailyCoordinate(currentMember);
330328

331-
if (coordinate.isEmpty()) {
332-
return List.of();
333-
}
334-
335-
List<CoordinateDetailsListResponse> details =
336-
coordinateRepository.findAllCoordinateDetailsByCoordinateId(
337-
coordinate.get().getId());
329+
return DailyCoordinatePreviewResponse.from(coordinate);
330+
}
338331

339-
if (details.isEmpty()) {
340-
return List.of();
341-
}
332+
@Override
333+
public List<CoordinateDetailsListResponse> getTodayCoordinateDetails() {
334+
final Member currentMember = memberUtil.getCurrentMember();
335+
final Coordinate coordinate = getTodayDailyCoordinate(currentMember);
342336

343-
return details.stream().map(DailyCoordinateClothResponse::from).toList();
337+
return coordinateRepository.findAllCoordinateDetailsByCoordinateId(coordinate.getId());
344338
}
345339

346340
@Override
@@ -487,4 +481,13 @@ private Coordinate getCoordinateById(Long coordinateId) {
487481
.orElseThrow(
488482
() -> new BaseCustomException(CoordinateErrorCode.COORDINATE_NOT_FOUND));
489483
}
484+
485+
private Coordinate getTodayDailyCoordinate(Member member) {
486+
return coordinateRepository
487+
.findDailyCoordinateByDateAndMemberId(LocalDate.now(), member.getId())
488+
.orElseThrow(
489+
() ->
490+
new BaseCustomException(
491+
CoordinateErrorCode.DAILY_COORDINATE_NOT_FOUND));
492+
}
490493
}

clokey-api/src/test/java/org/clokey/domain/coordinate/controller/CoordinateControllerTest.java

Lines changed: 91 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
88

99
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import java.time.LocalDate;
1011
import java.time.LocalDateTime;
1112
import java.util.List;
1213
import org.clokey.domain.coordinate.dto.request.CoordinateAutoCreateRequest;
@@ -1663,47 +1664,106 @@ class 최애_코디_조회_요청_시 {
16631664
}
16641665

16651666
@Nested
1666-
class 오늘의_코디_조회_요청_시 {
1667+
class 오늘의_코디_Preview_조회_요청_시 {
16671668

16681669
@Test
1669-
void 유효한_요청이면_오늘의_코디_정보를_반환한다() throws Exception {
1670+
void 유효한_요청이면_오늘의_코디_Preview를_반환한다() throws Exception {
16701671
// given
1671-
List<DailyCoordinateClothResponse> response =
1672+
LocalDate today = LocalDate.now();
1673+
DailyCoordinatePreviewResponse response =
1674+
new DailyCoordinatePreviewResponse(1L, "testImageUrl", LocalDate.now());
1675+
given(coordinateService.getTodayCoordinatePreview()).willReturn(response);
1676+
1677+
// when & then
1678+
ResultActions perform =
1679+
mockMvc.perform(
1680+
get("/coordinate/daily/today/preview")
1681+
.contentType(MediaType.APPLICATION_JSON));
1682+
1683+
perform.andExpect(status().isOk())
1684+
.andExpect(jsonPath("$.isSuccess").value(true))
1685+
.andExpect(jsonPath("$.code").value("COMMON200"))
1686+
.andExpect(jsonPath("$.message").value("성공입니다."))
1687+
.andExpect(jsonPath("$.result.coordinateId").value(1))
1688+
.andExpect(jsonPath("$.result.imageUrl").value("testImageUrl"))
1689+
.andExpect(jsonPath("$.result.date").value(today.toString()));
1690+
}
1691+
}
1692+
1693+
@Nested
1694+
class 오늘의_코디_Details_조회_요청_시 {
1695+
1696+
@Test
1697+
void 유효한_요청이면_오늘의_코디_Details를_반환한다() throws Exception {
1698+
// given
1699+
List<CoordinateDetailsListResponse> response =
16721700
List.of(
1673-
new DailyCoordinateClothResponse(
1674-
"https://image.example/cloth1.jpg",
1675-
"brand1",
1676-
"name1",
1677-
"category1",
1678-
"parent1"),
1679-
new DailyCoordinateClothResponse(
1680-
"https://image.example/cloth2.jpg",
1681-
"brand2",
1682-
"name2",
1683-
"category2",
1684-
"parent2"));
1685-
1686-
given(coordinateService.getTodayDailyCoordinateClothes()).willReturn(response);
1687-
1688-
ResultActions perform = mockMvc.perform(get("/coordinate/daily/today"));
1701+
new CoordinateDetailsListResponse(
1702+
1L,
1703+
50.2,
1704+
60.1,
1705+
1.5,
1706+
240.1,
1707+
1,
1708+
14L,
1709+
"testImageUrl1",
1710+
"testBrand1",
1711+
"testName1",
1712+
"testCategoryName1",
1713+
"testParentCategoryName1"),
1714+
new CoordinateDetailsListResponse(
1715+
2L,
1716+
50.2,
1717+
60.1,
1718+
1.5,
1719+
240.1,
1720+
2,
1721+
15L,
1722+
"testImageUrl2",
1723+
"testBrand2",
1724+
"testName2",
1725+
"testCategoryName2",
1726+
"testParentCategoryName2"));
1727+
1728+
given(coordinateService.getTodayCoordinateDetails()).willReturn(response);
1729+
16891730
// when & then
1731+
ResultActions perform =
1732+
mockMvc.perform(
1733+
get("/coordinate/daily/today/details")
1734+
.contentType(MediaType.APPLICATION_JSON));
1735+
16901736
perform.andExpect(status().isOk())
16911737
.andExpect(jsonPath("$.isSuccess").value(true))
16921738
.andExpect(jsonPath("$.code").value("COMMON200"))
1739+
.andExpect(jsonPath("$.message").value("성공입니다."))
1740+
.andExpect(jsonPath("$.result[0].coordinateClothId").value(1))
1741+
.andExpect(jsonPath("$.result[0].locationX").value(50.2))
1742+
.andExpect(jsonPath("$.result[0].locationY").value(60.1))
1743+
.andExpect(jsonPath("$.result[0].ratio").value(1.5))
1744+
.andExpect(jsonPath("$.result[0].degree").value(240.1))
1745+
.andExpect(jsonPath("$.result[0].order").value(1))
1746+
.andExpect(jsonPath("$.result[0].clothId").value(14))
1747+
.andExpect(jsonPath("$.result[0].imageUrl").value("testImageUrl1"))
1748+
.andExpect(jsonPath("$.result[0].brand").value("testBrand1"))
1749+
.andExpect(jsonPath("$.result[0].name").value("testName1"))
1750+
.andExpect(jsonPath("$.result[0].category").value("testCategoryName1"))
16931751
.andExpect(
1694-
jsonPath("$.result[0].imageUrl")
1695-
.value("https://image.example/cloth1.jpg"))
1696-
.andExpect(jsonPath("$.result[0].brand").value("brand1"))
1697-
.andExpect(jsonPath("$.result[0].name").value("name1"))
1698-
.andExpect(jsonPath("$.result[0].category").value("category1"))
1699-
.andExpect(jsonPath("$.result[0].parentCategory").value("parent1"))
1752+
jsonPath("$.result[0].parentCategory").value("testParentCategoryName1"))
1753+
.andExpect(jsonPath("$.result[1].coordinateClothId").value(2))
1754+
.andExpect(jsonPath("$.result[1].locationX").value(50.2))
1755+
.andExpect(jsonPath("$.result[1].locationY").value(60.1))
1756+
.andExpect(jsonPath("$.result[1].ratio").value(1.5))
1757+
.andExpect(jsonPath("$.result[1].degree").value(240.1))
1758+
.andExpect(jsonPath("$.result[1].order").value(2))
1759+
.andExpect(jsonPath("$.result[1].clothId").value(15))
1760+
.andExpect(jsonPath("$.result[1].imageUrl").value("testImageUrl2"))
1761+
.andExpect(jsonPath("$.result[1].brand").value("testBrand2"))
1762+
.andExpect(jsonPath("$.result[1].name").value("testName2"))
1763+
.andExpect(jsonPath("$.result[1].category").value("testCategoryName2"))
17001764
.andExpect(
1701-
jsonPath("$.result[1].imageUrl")
1702-
.value("https://image.example/cloth2.jpg"))
1703-
.andExpect(jsonPath("$.result[1].brand").value("brand2"))
1704-
.andExpect(jsonPath("$.result[1].name").value("name2"))
1705-
.andExpect(jsonPath("$.result[1].category").value("category2"))
1706-
.andExpect(jsonPath("$.result[1].parentCategory").value("parent2"));
1765+
jsonPath("$.result[1].parentCategory")
1766+
.value("testParentCategoryName2"));
17071767
}
17081768
}
17091769
}

0 commit comments

Comments
 (0)