회원가입 API를 구현하기 전에 필요한 UserErrorCode와 SignUpRequestDto를 준비한 과정을 기록해요.
@Getter
@RequiredArgsConstructor
public enum UserErrorCode implements ErrorCode {
USER_NOT_FOUND(404, "유저를 찾을 수 없습니다."),
DUPLICATE_EMAIL(409, "이미 사용 중인 이메일입니다."),
INVALID_PASSWORD(401, "비밀번호가 일치하지 않습니다.");
private final int status;
private final String message;
}
에러 코드를 enum으로 관리하면 두 가지 장점이 있어요.
첫째, 에러 코드가 한 곳에 모여있어서 관리하기 쉬워요.
둘째, 타입 안전성이 보장돼요. 문자열로 관리하면 오타가 나도 컴파일 에러가 안 나는데, enum은 컴파일 시점에 잡아줘요.
GlobalErrorCode → 공통 에러 (400, 401, 403, 404, 500)
UserErrorCode → 유저 도메인 에러
JwtErrorCode → JWT 에러
에러가 어느 도메인에서 발생했는지 명확하게 알 수 있어요. 나중에 도메인이 많아져도 관리하기 쉬워요.
domain
└── user
└── exception
└── UserErrorCode.java
에러 코드는 entity 패키지가 아닌 exception 패키지에 넣어요. entity 패키지는 DB와 매핑되는 클래스들만 모아두는 곳이거든요.
@Getter
@NoArgsConstructor
public class SignUpRequestDto {
@NotBlank(message = "이메일은 필수입니다.")
@Email(message = "이메일 형식이 올바르지 않습니다.")
private String email;
@NotBlank(message = "비밀번호는 필수입니다.")
@Size(min = 8, message = "비밀번호는 8자 이상이어야 합니다.")
private String password;
@NotBlank(message = "닉네임은 필수입니다.")
private String nickname;
}
Data Transfer Object. 계층 간 데이터를 전달하는 객체예요.
클라이언트가 보낸 JSON 데이터를 자바 객체로 받을 때 써요.
클라이언트 JSON
{
"email": "test@email.com",
"password": "12345678",
"nickname": "홍길동"
}
↓
SignUpRequestDto 객체로 변환
엔티티는 DB와 직접 연결된 객체예요. 외부에서 들어오는 데이터를 엔티티로 직접 받으면 두 가지 문제가 생겨요.
첫째, 보안 문제예요. 클라이언트가 role, id 같은 필드를 임의로 넣어서 보낼 수 있어요.
둘째, 설계가 지저분해져요. 엔티티는 DB 설계에 맞춰야 하고, DTO는 API 설계에 맞춰야 해요. 둘은 역할이 달라요.
@NotBlank → null이거나 빈 문자열이면 검증 실패
@Email → 이메일 형식이 아니면 검증 실패
@Size(min = 8) → 8자 미만이면 검증 실패
이 어노테이션들은 컨트롤러에서 @Valid를 붙여야 실행돼요.
// @Valid 없으면 검증 안 함 ❌
public ResponseEntity<Void> signUp(@RequestBody SignUpRequestDto request)
// @Valid 있으면 검증 함 ✅
public ResponseEntity<Void> signUp(@Valid @RequestBody SignUpRequestDto request)
스프링이 JSON을 객체로 변환할 때 기본 생성자가 필요해요. @NoArgsConstructor가 없으면 JSON 역직렬화가 안 돼요.
클라이언트 JSON → 기본 생성자로 객체 생성 → 각 필드에 값 주입
다음 포스팅에서는 AuthService와 AuthController를 구현해서 실제 회원가입 API를 완성하는 과정을 다룰 예정이에요.