Rafael

Engenheiro de Software

Olá, Eu sou Rafael. Estou construindo coisas para a web e mobile.

Um desenvolvedor dedicado a criar experiências digitais de alto desempenho, acessíveis e limpas. Eu me especializo em transformar problemas complexos em soluções de engenharia elegantes.

Validation no Spring Boot com Kotlin + Custom Validation (@EmailAvailable)

A validação no Spring Boot permite validar campos de DTOs usando anotações como:

  • @NotEmpty
  • @NotBlank
  • @Email
  • @Size
  • @Min
  • @Max

Para instalar as dependências coloque esse implementation no seu gradle:

GRADLE
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-validation")
}

Com uma simples anotação em nossos Dtos:

KOTLIN
import jakarta.validation.constraints.Email
import jakarta.validation.constraints.NotEmpty

data class PostCustomerRequest(
    @field:NotEmpty(message = "Nome não por ser vazio")
    var name:String,
    @field:Email(message = "Email inválido")
    var email:String
)

Ativando a validação no Controller, nota a anotação @Valid:

KOTLIN
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(
    @RequestBody @Valid request: PostCustomerRequest
) {
    customerService.create(request)
}

Quando alguma regra falhar, o Spring lançará:

KOTLIN
MethodArgumentNotValidException

Para tratar esse erro usamos um ControllerAdivace, se você ainda não viu como funciona o controller adivace acesse aqui. Vamos ao código do metódo:

KOTLIN
@ExceptionHandler(MethodArgumentNotValidException::class)
    fun handleMethodArgumentNotValidException(ex:MethodArgumentNotValidException,request:WebRequest):ResponseEntity<ErrorResponse>{
        val erro = ErrorResponse(
            httpCode = HttpStatus.UNPROCESSABLE_ENTITY.value(),
            message = Errors.ML001.message,
            internalCode = Errors.ML001.code,
            erros = ex.bindingResult.fieldErrors.map {
                FieldErrorResponse(it.defaultMessage?:"invalid",it.field)
            }
        )

        return ResponseEntity(erro, HttpStatus.UNPROCESSABLE_ENTITY)
    }

Além disso, podemos criar validações personalizadas, como verificar se um e-mail já existe no banco de dados. Vamos ver como fazer isso, primeiro vamos criar a classe EmailAvailable:

KOTLIN
import jakarta.validation.Constraint
import jakarta.validation.Payload
import kotlin.reflect.KClass

@Constraint(validatedBy = [EmailAvailableValidator::class])
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
annotation class EmailAvailable(
    val message: String = "Email já cadastrado",
    val groups: Array<KClass<*>> = [],
    val payload: Array<KClass<out Payload>> = []
)

Depois criamos a classe EmailAvailableValidator. Em ConstraintValidator<Nossa anotação,Tipo do atributo que vamos verificar>. Também chamamos o service para ter acesso ao banco de dados e antes de inserir algum dado, ele fala se o email já existe no banco de dados.

KOTLIN
import jakarta.validation.ConstraintValidator
import jakarta.validation.ConstraintValidatorContext
import mercado_livro.service.CustomerService

class EmailAvailableValidator(
    var customerService: CustomerService
):ConstraintValidator<EmailAvailable,String> {
    override fun isValid(value: String?, p1: ConstraintValidatorContext?): Boolean {
        if(value.isNullOrEmpty()){
            return false
        }

        return customerService.emailAvailable(value)
    }

}

Agora é só usar a nossa anotação:

KOTLIN
import jakarta.validation.constraints.Email
import jakarta.validation.constraints.NotEmpty
import mercado_livro.validation.EmailAvailable

data class PostCustomerRequest(
    @field:NotEmpty(message = "Nome não por ser vazio")
    var name:String,
    @field:Email(message = "Email inválido")
    @EmailAvailable
    var email:String
)

0 comentários

Deixe seu comentário