✨ Feat: 펫 디바이스 ID 중복 확인 기능 구현#152
Conversation
- 펫 등록 전 디바이스 ID 중복 여부를 확인하는 API 추가 - 펫 등록 시점에도 디바이스 ID 중복 검증 적용 - 디바이스 ID 중복 확인 요청/응답 DTO 및 서비스 로직 추가 - 디바이스 ID 중복 확인 서비스 테스트 추가 Closes DoDo-Project#151
There was a problem hiding this comment.
Code Review
This pull request introduces a new API endpoint and service logic to check for duplicate device IDs before registering a pet, along with corresponding request/response DTOs and unit tests. Feedback focuses on improving the API design: instead of throwing a PetException (409 Conflict) when a duplicate is found, the service should return a 200 OK response with available: false to properly utilize the response DTO's available field. Consequently, the Swagger documentation and unit tests should be updated to reflect this change. Additionally, the unused userDetails parameter in the controller's endpoint should be re-evaluated.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| public ResponseEntity<PetDeviceCheckResponse> checkDeviceId( | ||
| @Valid @RequestBody PetDeviceCheckRequest request, | ||
| @AuthenticationPrincipal UserDetails userDetails) { | ||
|
|
||
| UUID userId = UUID.fromString(userDetails.getUsername()); | ||
| log.info("디바이스 ID 중복 확인 요청 - User: {}, DeviceId: {}", userId, request.getDeviceId()); | ||
|
|
||
| return ResponseEntity.ok(petService.checkDeviceIdAvailability(request)); | ||
| } |
There was a problem hiding this comment.
현재 checkDeviceId 메서드에서 @AuthenticationPrincipal UserDetails userDetails를 받아 userId를 파싱하고 로그를 남기고 있지만, 실제 비즈니스 로직인 petService.checkDeviceIdAvailability(request)에는 userId가 전혀 사용되지 않고 있습니다.
만약 이 API가 로그인 여부와 상관없이 디바이스 ID의 중복 여부만 확인하는 퍼블릭 API라면, userDetails 매개변수를 제거하여 비인증 사용자도 접근할 수 있도록 개선할 수 있습니다. 반대로 반드시 인증된 사용자만 호출할 수 있어야 하는 보안 요구사항이 있다면 현재 구조를 유지하되, 단순히 로그 기록용으로만 사용되는 userId 파싱 과정의 필요성을 재검토해 보시는 것을 권장합니다.
| @Operation(summary = "디바이스 ID 중복 확인", description = "펫 등록 전에 디바이스 ID가 이미 다른 반려동물에 등록되어 있는지 확인합니다.") | ||
| @ApiResponses(value = { | ||
| @ApiResponse(responseCode = "200", description = "사용 가능한 디바이스 ID입니다.", | ||
| content = @Content(schema = @Schema(implementation = PetDeviceCheckResponse.class))), | ||
| @ApiResponse(responseCode = "400", description = "잘못된 요청입니다.", | ||
| content = @Content(mediaType = "application/json", | ||
| schema = @Schema(implementation = ErrorResponse.class), | ||
| examples = @ExampleObject(name = "400 Bad Request", value = "{\"status\": 400, \"message\": \"잘못된 요청입니다.\"}"))), | ||
| @ApiResponse(responseCode = "401", description = "로그인이 필요한 기능입니다.", | ||
| content = @Content(mediaType = "application/json", | ||
| schema = @Schema(implementation = ErrorResponse.class), | ||
| examples = @ExampleObject(name = "401 Unauthorized", value = "{\"status\": 401, \"message\": \"로그인이 필요한 기능입니다.\"}"))), | ||
| @ApiResponse(responseCode = "409", description = "이미 다른 반려동물에 등록된 디바이스 ID입니다.", | ||
| content = @Content(mediaType = "application/json", | ||
| schema = @Schema(implementation = ErrorResponse.class), | ||
| examples = @ExampleObject(name = "409 Conflict", value = "{\"status\": 409, \"message\": \"이미 다른 반려동물에 등록된 디바이스 ID입니다.\"}"))), | ||
| @ApiResponse(responseCode = "500", description = "서버 내부 오류가 발생했습니다.", | ||
| content = @Content(mediaType = "application/json", | ||
| schema = @Schema(implementation = ErrorResponse.class), | ||
| examples = @ExampleObject(name = "500 Internal Server Error", value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}"))) | ||
| }) |
There was a problem hiding this comment.
서비스 레이어(PetServiceImpl)에서 중복된 디바이스 ID에 대해 예외를 던지는 대신 available: false를 포함한 200 OK 응답을 반환하도록 변경할 경우, 컨트롤러의 Swagger 문서에서도 409 Conflict 응답 정의를 제거하고 200 OK 응답 설명을 그에 맞게 수정해야 합니다.
@Operation(summary = "디바이스 ID 중복 확인", description = "펫 등록 전에 디바이스 ID가 이미 다른 반려동물에 등록되어 있는지 확인합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "디바이스 ID 중복 확인 결과",
content = @Content(schema = @Schema(implementation = PetDeviceCheckResponse.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청입니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "400 Bad Request", value = "{\"status\": 400, \"message\": \"잘못된 요청입니다.\"}"))),
@ApiResponse(responseCode = "401", description = "로그인이 필요한 기능입니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "401 Unauthorized", value = "{\"status\": 401, \"message\": \"로그인이 필요한 기능입니다.\"}"))),
@ApiResponse(responseCode = "500", description = "서버 내부 오류가 발생했습니다.",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "500 Internal Server Error", value = "{\"status\": 500, \"message\": \"서버 내부 오류가 발생했습니다.\"}")))
})| public PetDeviceCheckResponse checkDeviceIdAvailability(PetDeviceCheckRequest request) { | ||
| if (petRepository.existsByDeviceId(request.getDeviceId())) { | ||
| throw new PetException(DEVICE_ID_DUPLICATED); | ||
| } | ||
|
|
||
| return PetDeviceCheckResponse.toDto("사용 가능한 디바이스 ID입니다.", true); | ||
| } |
There was a problem hiding this comment.
현재 checkDeviceIdAvailability 메서드는 디바이스 ID가 중복될 경우 PetException(DEVICE_ID_DUPLICATED) 예외를 던지도록 구현되어 있습니다. 하지만 응답 DTO인 PetDeviceCheckResponse에는 available이라는 boolean 필드가 존재합니다. 예외를 던지게 되면 클라이언트는 항상 available이 true인 응답만 받거나 에러 응답(409 Conflict)을 받게 되므로, available 필드가 무색해집니다.
중복 확인(Check) API는 예외를 던지기보다 200 OK 응답과 함께 available: false를 반환하는 것이 일반적인 REST API 설계에 부합하며, 클라이언트 측에서도 불필요한 에러 핸들링 로직을 줄일 수 있습니다. 중복 여부에 따라 적절한 메시지와 available 값을 반환하도록 변경하는 것을 권장합니다.
| public PetDeviceCheckResponse checkDeviceIdAvailability(PetDeviceCheckRequest request) { | |
| if (petRepository.existsByDeviceId(request.getDeviceId())) { | |
| throw new PetException(DEVICE_ID_DUPLICATED); | |
| } | |
| return PetDeviceCheckResponse.toDto("사용 가능한 디바이스 ID입니다.", true); | |
| } | |
| public PetDeviceCheckResponse checkDeviceIdAvailability(PetDeviceCheckRequest request) { | |
| if (petRepository.existsByDeviceId(request.getDeviceId())) { | |
| return PetDeviceCheckResponse.toDto("이미 다른 반려동물에 등록된 디바이스 ID입니다.", false); | |
| } | |
| return PetDeviceCheckResponse.toDto("사용 가능한 디바이스 ID입니다.", true); | |
| } |
| @Test | ||
| @DisplayName("디바이스 ID 중복 확인 실패: 이미 사용 중인 ID면 예외가 발생한다.") | ||
| void checkDeviceIdAvailability_Fail_DuplicateDeviceId() { | ||
| log.info("디바이스 ID 중복 확인 실패 테스트를 시작합니다."); | ||
| // given | ||
| String duplicateDeviceId = "DUPLICATE_DEV"; | ||
| PetRequest.PetDeviceCheckRequest request = PetRequest.PetDeviceCheckRequest.builder() | ||
| .deviceId(duplicateDeviceId) | ||
| .build(); | ||
|
|
||
| log.info("요청한 디바이스 ID가 이미 존재한다고 설정합니다."); | ||
| given(petRepository.existsByDeviceId(duplicateDeviceId)).willReturn(true); | ||
|
|
||
| // when | ||
| log.info("중복 확인 요청 시 예외가 발생하는지 확인합니다."); | ||
| PetException exception = assertThrows(PetException.class, () -> | ||
| petService.checkDeviceIdAvailability(request) | ||
| ); | ||
|
|
||
| // then | ||
| log.info("발생한 예외 코드가 DEVICE_ID_DUPLICATED인지 검증합니다."); | ||
| assertEquals(PetErrorCode.DEVICE_ID_DUPLICATED, exception.getErrorCode()); | ||
| log.info("디바이스 ID 중복 확인 실패 테스트가 통과되었습니다."); | ||
| } |
There was a problem hiding this comment.
PetServiceImpl에서 checkDeviceIdAvailability 메서드가 예외를 던지는 대신 available: false를 반환하도록 변경됨에 따라, 관련 테스트 코드도 예외 발생 여부 대신 반환된 DTO의 available 필드 값을 검증하도록 수정해야 합니다.
@Test
@DisplayName("디바이스 ID 중복 확인 실패: 이미 사용 중인 ID면 false를 반환한다.")
void checkDeviceIdAvailability_Fail_DuplicateDeviceId() {
log.info("디바이스 ID 중복 확인 실패 테스트를 시작합니다.");
// given
String duplicateDeviceId = "DUPLICATE_DEV";
PetRequest.PetDeviceCheckRequest request = PetRequest.PetDeviceCheckRequest.builder()
.deviceId(duplicateDeviceId)
.build();
log.info("요청한 디바이스 ID가 이미 존재한다고 설정합니다.");
given(petRepository.existsByDeviceId(duplicateDeviceId)).willReturn(true);
// when
log.info("디바이스 ID 중복 확인 서비스 로직을 호출합니다.");
PetResponse.PetDeviceCheckResponse response = petService.checkDeviceIdAvailability(request);
// then
log.info("사용 가능 여부가 false이고 적절한 메시지가 반환되었는지 검증합니다.");
assertNotNull(response);
assertFalse(response.isAvailable());
assertEquals("이미 다른 반려동물에 등록된 디바이스 ID입니다.", response.getMessage());
log.info("디바이스 ID 중복 확인 실패 테스트가 통과되었습니다.");
}- 디바이스 ID 중복 확인 컨트롤러에서 불필요한 UserDetails 파라미터 제거 - 비즈니스 로직에 사용하지 않는 userId 파싱 로직 제거 - 디바이스 ID 기준 로그만 남기도록 정리 Closes DoDo-Project#151
- 디바이스 ID 중복 확인 시 예외 대신 available=false 응답 반환 - 중복 확인 API Swagger 문서에서 409 응답 제거 - 중복 확인 실패 테스트를 응답 DTO 검증 방식으로 수정 Closes DoDo-Project#151
📄 작업 내용 (Description)
🔗 관련 이슈 (Related Issues)
✅ 체크리스트 (Checklist)
Style)Test)📸 스크린샷 (Screenshots)
💬 기타 사항 (Etc)
디바이스 ID 중복 확인하는 기능이 재등록할때만 확인을 해서 따로 api 만들었습니다.