[Spring] 중복 확인 Rest API 설계
아이디와 닉네임에 대해 중복을 확인할 수 있는 Rest API이다.
1. Entity
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name="User")
public class User {
@Id
@Column(name="user_id", unique = true)
private String id; // 아이디
@Column(name = "user_nickname", unique = true, length = 20)
private String nickname; // 닉네임
@Builder
public User(String id, String nickname){
this.id = id;
this.nickname = nickname;
}
}
아이디와 닉네임 컬럼을 생성해준다.
기본생성자는 동일 패키지나 파생 패키지에서만 사용할 수 있도록 PROTECTED로 설정해줬다.
2. Repository
public interface UserRepository extends JpaRepository<User, String> {
Optional<User> findByNickname(String nickname);
Optional<User> findById(String id);
}
서비스에서 사용하기 위해 findByNickname과 findById를 레포지토리에 생성해준다.
3. Service
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
public boolean checkDuplicateNickname(String username) {
return !userRepository.findByNickname(username).isPresent();
}
public boolean checkDuplicateId(String id){
return !userRepository.findById(id).isPresent();
}
}
레포지토리에서 닉네임이나 아이디를 찾은 후, 그 닉네임이나 아이디가 존재한다면 false를 리턴시키도록 설계했다.
4. ApiResponseDto
@Getter
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ApiResponseDto<T> {
private final int code;
private final String message;
private T data;
public static ApiResponseDto success(SuccessStatus successStatus) {
return new ApiResponseDto<>(successStatus.getHttpStatus().value(), successStatus.getMessage());
}
public static <T> ApiResponseDto<T> success(SuccessStatus successStatus, T data) {
return new ApiResponseDto<T>(successStatus.getHttpStatus().value(), successStatus.getMessage(), data);
}
public static ApiResponseDto error(ErrorStatus errorStatus) {
return new ApiResponseDto<>(errorStatus.getHttpStatus().value(), errorStatus.getMessage());
}
public static <T> ApiResponseDto<T> error(ErrorStatus errorStatus, T data) {
return new ApiResponseDto<T>(errorStatus.getHttpStatus().value(), errorStatus.getMessage(), data);
}
}
요청에 대해 공통적으로 응답을 보낼 수 있도록 ApiResponseDto를 생성해줬다. 성공과 에러 발생 시에 대해 모두 생성해줬다.
5. SuccessStatus
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum SuccessStatus {
CREATE_ID_SUCCESS(HttpStatus.OK, "사용 가능한 아이디입니다."),
CREATE_NICKNAME_SUCCESS(HttpStatus.OK, "사용 가능한 닉네임입니다.")
;
private final HttpStatus httpStatus;
private final String message;
}
성공했을 때 어떤 HTTP 상태코드와 메세지를 보낼지 작성해줬다.
6. ErrorStatus
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum ErrorStatus {
/*
CONFLICT
*/
CONFLICT_ID_EXCEPTION(HttpStatus.CONFLICT, "이미 등록된 id입니다."),
CONFLICT_NICKNAME_EXCEPTION(HttpStatus.CONFLICT, "이미 등록된 닉네임입니다.")
;
private final HttpStatus httpStatus;
private final String message;
}
중복됐을 때 에러 메세지를 처리하기 위해 ErrorStatus 코드도 작성해줬다.
7. Controller
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
private final UserRepository userRepository;
@ApiOperation(value = "아이디 중복 확인", notes = "해당 id가 이미 존재한다면 true, 존재하지 않다면 false를 반환합니다.")
@ApiImplicitParam(name = "id", value = "사용자가 생성한 id")
@GetMapping("/checkDuplicateId/{userId}") // 아이디 중복 확인
public ApiResponseDto<String> checkDuplicateId(@PathVariable String userId) {
return userService.checkDuplicateId(userId) ? ApiResponseDto.success(SuccessStatus.CREATE_ID_SUCCESS, userId)
: ApiResponseDto.error(ErrorStatus.CONFLICT_ID_EXCEPTION, userId);
}
@ApiOperation(value = "닉네임 중복 확인", notes = "해당 닉네임이 이미 존재한다면 true, 존재하지 않다면 false를 반환합니다.")
@ApiImplicitParam(name = "nickname", value = "사용자가 생성한 닉네임")
@GetMapping("/checkDuplicateNickname/{nickname}")
public ApiResponseDto<String> checkDuplicateNickname(@PathVariable String nickname) {
return userService.checkDuplicateNickname(nickname) ? ApiResponseDto.success(SuccessStatus.CREATE_NICKNAME_SUCCESS, nickname)
: ApiResponseDto.error(ErrorStatus.CONFLICT_NICKNAME_EXCEPTION, nickname);
}
}
응답은 ApiResponseDto에 만들어뒀던 success나 error로 처리를 할 것이다.
우선 isDuplicateId / isDuplicateNickname 변수에 서비스단에서 만들어줬던 중복 처리를 해준다.
존재한다면 false, 존재하지 않다면 true를 리턴한다. 즉 false일 경우 사용 불가능하고 true일 경우 사용할 수 있다.
그 결과를 삼항연산자에 담에 true일 시 success에 데이터를 넘기고 false일 경우 error에 데이터를 넘겨 처리한다.
SuccessStatus와 ErrorStatus에 작성해뒀던 enum을 토대로 코드를 작성하면 된다.
참고로 @ApiOperation과 @ApiImplicitParam은 스웨거 사용을 위한 어노테이션이니 생략해도 된다!
그럼 중복 확인이 잘 되는지 포스트맨으로 확인해보자!
다음과 같이 회원가입을 해줬다. 아이디는 "monggu", 닉네임은 "jy"이다.
아이디 중복 확인을 해보자.
"monggu"를 사용하려고 하면 이미 등록된 id라는 에러 메세지가 잘 뜬다.
다른 아이디를 사용해보자.
중복되지 않는 아이디는 사용 가능하다는 메세지가 출력되는 것을 확인할 수 있다.
이번엔 닉네임 중복 확인을 해보자!
회원가입할 때 사용했던 "jy" 닉네임은 이미 등록된 닉네임이라며 사용할 수 없다는 메세지가 출력된다.
중복되지 않는 닉네임을 사용하면 사용 가능한 닉네임이라고 출력되는 메세지를 확인할 수 있다!