Validate dữ liệu Rest API trong Spring Boot

Đối với các Rest API việc validate dữ liệu đầu vào là vô cùng quan trọng có thể giúp chúng tránh được nhiều lỗi trong quá trình thực thi business logic của dự án. Để tiện lợi hơn trong việc validate, spring boot đã cung cấp một công cụ để thực hiện các validate gọn gàng và nhanh chóng hơn.

Maven dependency

Như đã đề cập ở trên, thì trong bài này chúng ta sẽ triển khai validate dữ liệu cho Rest API. Do vậy chúng ta bắt buộc phải thêm spring-boot-starter-web. Ngoài ra, mình thêm Lombok dependency để sinh các hàm constructor, getter, tự động.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

Cuối cùng, dependency quan trọng nhất của chúng ta là spring-boot-starter-validation cung cấp các annotation dùng để validate dữ liệu.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Tạo DTO

Trong hầu hết các Rest API đều sử dụng các DTO như là một class dùng để giao tiếp giữa client và server, chúng ta không nên sử dụng trực tiếp một entity để truyền vào nhận giữa client-server vì đôi lúc có những thông tin trong entity không nên trả về cho server ví dụ như password của user. Như vậy sử dụng DTO cho phép chúng ta toàn quyền quyết định những dữ liệu dùng trong giao tiếp giữa client và server.

Tạo một UserDTO

package com.deft.validationrest;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;

@Getter
@Setter
@NoArgsConstructor
public class UserDTO {

    private long id;

    @NotBlank(message = "Name is mandatory")
    private String name;

    @NotBlank(message = "Email is mandatory")
    private String email;

    @Min(value = 18, message = "Age can not be less than 18")
    @Max(value = 50, message = "Age can not be greater than 50")
    private Integer age;

}

Trong đó @NotBlank được sử dụng với một trường dữ liệu ngầm hiểu rằng dữ liệu từ client truyền lên không được để trống trường này.

Chúng ta cũng có thể kết hợp nhiều annotation cho cùng một trường dữ liệu như @Min được sử dụng để chỉ định một giá trị không thể nhỏ một giá trị được chỉ định và @Max với một giá trị và giá trị gửi lên phải bé hơn hoặc bằng.

Tạo Controller

Cuối cùng, sau khi có DTO, chúng ta sẽ tiến hành tạo controller để nhận các request từ client gửi lên server, sau đó tiến hành validate dữ liệu.

package com.deft.validationrest;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.MethodArgumentNotValidException;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

@RestController
public class UserController {

    @PostMapping("/users")
    ResponseEntity<String> addUser(@Valid @RequestBody UserDTO userDTO) {
        return ResponseEntity.ok("User is valid");
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return errors;
    }

}

Trong đó, @Valid annotation được sử dụng với các tham số đầu vào trong Rest method, Spring Boot sẽ tìm kiếm những tham số được chú thích với annotation để thực hiện các kiểm tra như đã định nghĩa trước đó. Khi các tham số không đáp ứng đủ điều kiện mà chúng ta đã đặt ra trước đó, Spring Boot sẽ ném MethodArgumentNotValidException.

Do vậy chúng ta cần sử dụng @ExceptionHandler annotation để bắt MethodArgumentNotValidException ném ra từ Spring Boot khi có lỗi validate để xử lý và trả về kết quả lỗi cho client.

Để kiểm thử chúng ta sẽ khởi chạy ứng dụng và request với những thông tin không hợp lệ

curl -d "{\"age\":10}" -H "Content-Type: application/json" -X POST http://localhost:8080/users
---
{
    "name": "Name is mandatory",
    "age": "Age can not be less than 18",
    "email": "Email is mandatory"
}

Mã nguồn được mình công khai trên gitlab để các bạn tiện theo dõi: validate-spring

Nguồn tham khảo

https://www.baeldung.com/spring-boot-bean-validation

2 2 votes
Article Rating
Subscribe
Notify of
guest
2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
2
0
Would love your thoughts, please comment.x
()
x