Prunesh
Prunesh

Reputation: 1

I can't understand why DTO validation doesn't work

I have a DTO

data class UserRegistrationDto(
    @field:NotBlank(message = "{username.notblank}")
    @field:Size(min = 3, max = 20, message = "{username.size}")
    @field:Pattern(
        regexp = "^[a-zA-Z0-9_]+$",
        message = "{username.pattern}"
    )
    val username: String,

    @field:NotBlank(message = "{email.notblank}")
    @field:Email(message = "{email.invalid}")
    @field:Size(max = 100, message = "{email.size}")
    val email: String,

    @field:NotBlank(message = "{password.notblank}")
    @field:Size(min = 8, max = 50, message = "{password.size}")
    @field:Pattern(
        regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,}$",
        message = "{password.pattern}"
    )
    val password: String
)

data class UserResponseDto(
    val id: Long?,
    val username: String,
    val email: String
)

But it doesn't work with my userservice

@Service
class UserService(
    private val userRepository: UserRepository,
    private val passwordEncoder: PasswordEncoder
) {
    private val logger = LoggerFactory.getLogger(UserService::class.java)

    @Transactional
    fun registerNewUser(dto: UserRegistrationDto): UserResponseDto {
        validateUsername(dto.username)
        
        checkUserUniqueness(dto)

        val user = createNewUser(dto)
        val savedUser = userRepository.save(user)

        logger.info("User registered successfully: username={}", dto.username)

        return mapToUserResponseDto(savedUser)
    }

    private fun validateUsername(username: String) {
        val trimmedUsername = username.trim()

        when {
            trimmedUsername.length < 3 -> {
                logger.warn("Username validation failed: too short ({})", trimmedUsername.length)
                throw ValidationException("Username must be at least 3 characters long")
            }
            trimmedUsername.length > 20 -> {
                logger.warn("Username validation failed: too long ({})", trimmedUsername.length)
                throw ValidationException("Username must not exceed 20 characters")
            }
            !trimmedUsername.matches(Regex("^[a-zA-Z0-9_]+$")) -> {
                logger.warn("Username validation failed: invalid characters")
                throw ValidationException("Username can only contain letters, numbers, and underscores")
            }
        }
    }

    private fun checkUserUniqueness(dto: UserRegistrationDto) {
        val errors = mutableListOf<String>()

        if (userRepository.existsByUsername(dto.username)) {
            logger.warn("Username already exists: {}", dto.username)
            errors.add("Username already exists")
        }
        if (userRepository.existsByEmail(dto.email)) {
            logger.warn("Email already exists: {}", dto.email)
            errors.add("Email already exists")
        }

        if (errors.isNotEmpty()) {
            throw ValidationException(errors.joinToString("; "))
        }
    }
}

The problem is that I can restrict the input of all this data in my application, but I would like to limit this at the API level so that a direct request with inconsistent data does not pass

When I make an API request in Postman, everything goes well for me, but an error should appear

I have already tried several different approaches, but nothing changes

Upvotes: 0

Views: 55

Answers (0)

Related Questions