Spring Rest API validation should be in DTO or in entity?
Asked Answered
J

4

29

In which tier should the validation be in a Spring Boot Rest API. I have some models, endpoints and DTOs. I added some @NotNull and @Size annotations in the DTO. I added the @Valid annotation in the endpoint along with the @RequestParam annotation.

But now I'm wondering if I should put validation in the @Entity classes as well? I feel like it would be a duplication of code. But I read that a tier should never rely on another one.

Judges answered 16/2, 2017 at 17:4 Comment(2)
Validation should be made only in the presentation layer (DTO) and Entities should never reach to the presentation layer.Gillman
So no restriction annotations in the entities? For example, when you create a db without an ORM, you specify VARCHAR(30). Which limits the string length.Judges
R
39

It's ironic how many people truly believe that validation should be something we partake upon in our controllers or the value objects which they exchange with business code and at no other place should there be concern for state validation.

We should always strive to perform validation at multiple stages of any application.

Consider for the moment a controller that accepts a value object that you intend to use to change a business entity in some service and that value object contains only a subset of fields that you intend to manipulate in a larger entity. You validate the value object in your presentation tier and pass that to your service which fetches the entity, takes the values from the value object and sets them on the appropriate entity. Perhaps that service method manipulates other fields too.

What guarantee do we have that the state of that entity is valid?

While we validated the value object was valid, we only validated those inputs within the context of the subset of fields which were supplied. We didn't validate that those values in conjunction with the other existing state of the entity were still valid.

It's also important to try and guard against developer mistakes too. Test cases only get you so far and we all can agree we don't validate the validity of every combination of values in our tests. We often target very specific cases and scenarios and draw conclusions from there.

By applying validation not only to our presentation value objects but to our entities, you not only allow your test cases to focus on broad feature validation but you guarantee that your data store state is never compromised by the application.

Rosaline answered 17/2, 2017 at 5:4 Comment(0)
C
19

After thinking about it for a while, I decided that the best approach is to validate on both layers. I'll explain why.

Imagine that you have a User entity with a name field and your application business logic requires it not to be null. You also have a UserDTO with the same name field.

I assume that all your validations on both, entity and DTO, will be made using the java.validation API.

If you validate only on the controller, then you're safe against persisting an invalid entity, but only from a incoming request. If you have a service that manipulates the entity, it may persist the entity in an invalid state without you noticing (unless there is a null check on the database column).

Then, you can think: "OK, I'll move the validation annotations from the DTO to the entity and all will be fine". Well, yes and no!

If you validate only on the entity, you will be safe from both, incoming requests and on your service layer, however you may have a performance problem.

According to Anghel Leonard on its book Spring Boot Persistence Best Practices, every time you load an entity from the database, Hibernate wastes memory and CPU to maintain the entity state on the persistence context, even if the entity is in "read only mode".

Now, think about it. If the user name is null and you validate it only on the entity, this means that you:

  1. Started a transaction
  2. Loaded the entity
  3. Changed the entity
  4. Flushed the persistence context
  5. Rolled back the transaction

Many of these operations can be expensive and you did it all just to throw it on the trash, when you could simply have never done anything if you had validated the user name earlier.

So, my advice is to validate on both layers. The annotations make it so easy that you not even have an excuse to not do it. Even complex validations can be made writing custom validators, which can then be reused on a lot of other places

Also, here is a link to the book I mentioned, I hope you enjoy: https://www.amazon.com.br/dp/B087WS81RK/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

Cotterell answered 24/7, 2020 at 4:22 Comment(2)
great arguments, thx! :)Way
In the case where the controller calls a service, and assuming that the controller works with DTOs and the service with Entities, doesn't this mean that you are now double validating? i.e at the controller as well as at the service. If so, doesn't that 1) constitute a performance issue, especially when validators are accessing a database? 2) Increase the maintenance workload for keeping validations rules the same in DTOs and Entities at all times. My question then is, is the performance hit significant enough to live with these two limitations?Ferneferneau
W
1
Input needs to be validated first you can use the below validations in dto 

@NotBlank("Username must not be null")
@Size(max=10)
private String userName;

@Email
@NotBlank
@Size(min =10,max=100,message ="emaild id must be valid")
private String emailId;
Whitechapel answered 30/6, 2023 at 9:56 Comment(0)
B
0

In entity you should add constraints that required your data to be in healthy state and all the validation logic should be in DTO because, your RestController serve DTOs and it is the responsibility of controller to check for validation before mapping to entity.

Bluecollar answered 17/2, 2017 at 4:26 Comment(1)
Sushil, after mapping dto to entity, there could be need for modifications to the entity as well. Therefore, it would be wise to valid entity as well. Also, service layer does not want to assume what it gets from controller is a valid entity.Scapegrace

© 2022 - 2024 — McMap. All rights reserved.