How to map DTO to Entity to insure good practice validation in spring-boot / angular app?

Viewed 21

I have a form wizard in Angular (with next button on each page), this wizard is for saving Product, the Product has many fiedls and each angular componenet within thw wizard deal with a sublist of fields/columns.

In order to save to the database, I had to make some fields as nullable=true (this annotations are in the DTO itself and not on entity level) and I was able to implement this solution by adding a status field in the Product table which mean the application recogonize the entity or return the Product in search for example only if the status == true (this is done at the end of the wizard).

The downside is that I can't make DTO fields as @NotNull for example, so that's means the following code won't work automatically,

@ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponseDTO> handleValidationError(MethodArgumentNotValidException exception) {

         List<FieldErrorMessageDTO> errorList = new ArrayList<>();
         List<ObjectError> errors = exception.getBindingResult().getAllErrors();
         errors.stream().forEach(err -> { 
             if (err instanceof FieldError) {
                 FieldError fieldErr = (FieldError) err;
                 errorList.add(new FieldErrorMessageDTO(fieldErr.getField(), fieldErr.getDefaultMessage(), fieldErr.getCode()));
             }
         });                 
         return new ResponseEntity<ErrorResponseDTO>(new ErrorResponseDTO(null, errorList, new Date()), HttpStatus.BAD_REQUEST);                                                    
    }

So, the question is if I must split the ProductDTO to 10 DTOs (which means adding more contrllers) in order to solve this problem? there is no such requirement that Postman will able to send json with the full product details at once, Product is creates by the angular app only.

Another issue is that, 10 DTO meaning addiotnal 10 updateProduct controller methods! Cause if not, theortically, user might get error to console when field ais not valid even he is not on this page.

With 1 DTO I will still need to create more contrllers and do custom validation insead of generic one, if you suggest one can you provide example ?

Thanks!

1 Answers

After searching and searching I found about group validation sollution. It's for MVC but I think it can be done for rest contrlllers as well. The main idea is the mark each field in the DTO class, the mark is done by interface. Snippet from the DTO class:

@SamePasswords(groups = {Account.ValidationStepTwo.class})
public class Account implements PasswordAware {

    @NotBlank(groups = {ValidationStepOne.class})
    private String username;

     interface ValidationStepOne {
        // validation group marker interface
    }

    interface ValidationStepTwo {
        // validation group marker interface
    }

Each step will have its own controller end point where I will indicate which interface to use:

 @RequestMapping(value = "stepOne", method = RequestMethod.POST)
    public String stepOne(@Validated(Account.ValidationStepOne.class) Account account, Errors errors) {
        if (errors.hasErrors()) {
            return VIEW_STEP_ONE;
        }
        return "redirect:stepTwo";
    }

The solution assume that you haved defined @SamePasswords – custom constraints, that must define groups attribute, which I'm not sure about at this stage.

Related