I'd like to have your expert explanations about an architectural question. Imagine a Spring MVC webapp, with validation API (JSR 303). So for a request, I have a controller that handles the request, then passes it to the service layer, which passes to the DAO one.
Here's my question. At which layer should the validation occur, and how ?
My though is that the controller has to handle basic validation (are mandatory fields empty ? Is the field length ok ? etc.). Then the service layer can do some tricker stuff, that involve other objets. The DAO does no validation at all.
BUT, if I want to implement some unit testing (i.e. test layers below service, not the controllers), I'll end up with unexpected behavior because some validations should have been done in the Controller layer. As we don't use it for unit testing, there is a problem.
What is the best way to deal with this ? I know there is no universal answer, but your personal experience is very welcomed.
Thanks a lot.
Regards.
In your service unit tests, craft your test data as though it passed all controller level validation checks - essentially assume that the controller level validation will work perfectly and your service will only ever receive data that is valid from the controller's perspective. Then, test each of those validation cases in the controller's unit tests. Finally, include integration tests which fail validation on both levels and make sure none get through.
Related
I started using Spring MVC to build my first REST API :) Now I struggle a bit of where to put which logic. I read the following:
#RestController: Handles requests, defines the API the user can use
#Service: Contains the business logic
#Repository: Abstracts away from access to DB
In an easy first example, I saw the flow was like this: RestController calls Service, Service calls Repository. In the first step, I did it like this.
Now I want to use ResponseEntity - I hear it is good practice to use that. But now I start wondering: Should the service layer return ResponseEntity or just the instances of the domain model?
To show what I mean (yes, I am a big football fan):
#GetMapping("/clubs")
public ResponseEntity<List<FootballClub>> getAllClubs(#RequestParam String footballLeague) {
List<FootballClub> clubs = service.getAllClubs(footballLeague);
return new ResponseEntity(...);
}
Is it best practice to do it like this or to let the Service return the ResponseEntity? I am new to Spring MVC. I read some articles on Stackoverflow and some explain the general setup. But I could not find how to deal with for instance ResponseEntity.
I think you can argue that ResponseEntity should also be in Service as you might need to return method not allowed or something like this and determining whether to return a method not allowed ResponseEntity or an OK Entity could be considered part of the business logic. But I don't know.
Thank you!
Short Answer
Yes, Service returning domain object should be preferable to a Service returning ResponseEntity<>.
Long Answer
There is no best practices. Having said that, you should think of implementing something like Hexagonal or Layered architecture. In Hexagonal architecture, application/domain logic is confined in application/domain layer which is separated from presentation, persistence/infrastructure layer. Interfaces are defined in application layers (called ports) and implementation is provided in infrastructure layer (called adapters). There is an excelled article on this.
Concepts like Service, Repository is taken from DDD. To know more about DDD you can check Vaughn Vernon book Implementing Domain-Driven Design.
The service should returns instances of the domain model. The ResponseEntity (which is related to the Response the controller returns after request elaboration) should be created at controller level.
We got this design:
Rest Controller -> Calling Service -> Calling JPA DAOs
Let say we save employee. And we have a requirements to validate employee name.
IEmployeeService.saveEmployee(Employee emp)
EmployeeController.saveEmployee(Employee emp)
Option 1: I can inject JSR303 annotations on Employee and Let Rest Controller validate it as part of automatic validation.
Option 2: I validate in service method and raise exception and let controller to return proper JSON of that exception.
Seems like service should have validation anyways... but in presence of JSR303 annotations controller is doing everything, hence there seem to be duplication of logic if service does those checks as well.
How do you approach? Everybody's comments welcome and will be appreciated.
Thanks
Babar
IMHO, the standard way is to use both Opt 1 and Opt 2.
But, you have to define what's going to be validated in each layer.
This is my favorite approach:
Validate field constraints in Controller. This include: Date format, string length, min, max, null... validation
Validate business logic constraint in Service. Include: Unique, exist check, from date < to date, max items per group of entities...
One side note: Entity should never been exposed to outside world. We should have some kind of converter logic to convert entity to output JSON/model
Ideally your web facing part should have your validation logic implemented. The service layer should be purely for the business part of project. It is also security best practice before it reach to your service layer code. Nowadays people do mix-up layer and want to do everything in same layer. The jsr-303 annotation are bean level validation. So normally it is applied at a place where model comes into picture.
So you can do that at
controller layer: to validate your input and other min/max range and basic validation.
service layer: To have any specific validation at service layer by Autowiring javax.validation.Validator.
I would do both.
In your example you seem to have both methods refer to Employee, which might be possible in very simple scenarios, but in practical scenarios this is not.
It is more likely that you are going to have an EmployeeDTO which has JSON properties mapped to Java object fields. You might even have more specific DTOs to specific employee operations (for example change password), depending on what forms your UI is exposing. This will be received by your controller, and JSR303 can help do syntactic validations, like checking the string is not empty, that a name does not contain numbers etc.
The DTO should not bleed in to the service, but its data should be translated to whatever the service is expecting, which should be decoupled from the inputs of the controller.
Your Service will then receive an Employee. This could be a JPA Entity if it makes sense, or some other intermediate domain object related to the operation being performed. The creation of the Employee should ideally already enforce some simple checks (for example non null checks), to ensure that the object is consistent after construction. The service itself should then validate what it is receiving, independently of what the controller validates. The service could be used by other controllers, or invoked by other services in the future, so you should always program defensively. The service could also do more logical checks (for example does another employee with the same ID but different details exist? etc.) This will do business logic validation that will enforce further robustness.
If you see a lot of common code between the DTO and the Entity, or intermediate objects, there are also mapper utility libraries which can help you avoid repetition, like MapStruct.
Suppose the architecture is such that there is
Struts framework or jersey resource
Facade layer
Business layer
Data access object layer DAO
Though the Input field validation is to be done at presentation layer i.e Struts Action class or jersey resource class
But my question is where should business level validation to be done and same outcome to be passed to UI.
I.e suppose resource is
employee/{employeeId} method DELETE
Now first need to verify that employeeId exist or not , so for that validation should be done at resource level, facade level or business level and how it should be any best practice is highly appreciated.
Also please note that this business validation require DAO layer access since to check in DB if employeeId really exist.
Thanks in advance
There are as many arguments as approaches for what you're asking. I prefer to leave validation to the business layer and let the service layers above that more or less just handle routing and error reporting. Good luck!
Depends on the architectures and frameworks you have choosen.
In example: If you have one Database but a server-farm, the Validation should be more near the Database. If you can lock/unlock the Database in the DAO, you shall lock the employee-row first before you validate.
Also it depends on the configuration:
If you use optimistic or pessimistic locking.
If you have a #version field on the entitys.
many many more.
I suggest you to write logic related database access at dao layer, which returns the result to service layer and it returns to the Action class. And you should validate it in your action class.
For quite some time I try to figure out where validation of user input should take place in a Spring MVC application. In many online blogs and tutorials I basically read that a controller should validate the users input and, if invalid, respond to the user by showing a page containing the error message. My current understanding of the Spring and Spring MVC layering system, however, is that a Controller is a only shallow interface between the application logic (service layer) and the "web world", allowing usage of the service layer from the web. Also, as far as I can see, Spring MVC does only provide reasonable tools for validation in a Controller.
If now validation takes place in a Controller, if at some later point I want to untie the application logic from the "web world", validation logic must be reimplemented in the new environment (e.g. a desktop application using Swing). In my opinion, the ability to decide which operations are "valid" on domain objects, and what "valid" states such objects may have, is core part of the service layer, and not the concern of some other part of the application (e.g. Controllers).
In this context, why is it "good practice" to place input validation logic in the controller layer and not the service layer?
A common approach is to do validation on both places. But if you are talking about #Valid, from my experience it is nicer to put on Controllers level.
It also depends what kind of validation logic we are talking about. Let's say you have a bean:
#Data
public class MyBean {
#NotNull private UUID someId;
#NotEmpty private String someName;
}
It would make sense for this bean to be annotated with #Valid on the controller level so it doesn't even reach the service. There is no benefit to putting the #Valid on the service method, because why would you propagate it further while you can immediately in the controller decide if it is that kind of valid or not.
Then there is a second type of validation: business logic validation. Let's say for the same bean that the someId property is a timeUUid and its timestamp needs to be at most 2 days after some event occurred, in other case, the bean should be discarded by the service.
That seems like a business logic validation case, because by just looking at the bean, you wouldn't be able to validate it, unless you apply some logic to it.
Since both approaches to validation actually validate different things, it is obvious to see that each of your MVC components - Model, View and Controller, do their own validation and it should be reasonable about what it validates without introducing dependency to the other components.
As for showing the error to the user, yes, the Errors object is indeed intended to be used for bean validation at controller level, but you can design some filter that catches exceptions on any level and then pretty formats it for the user. There are many approaches to it, and I am not sure if Spring prescribes that any is better than the other.
Depending on different resolve mechanism (as in, for example, jstl or jackson or something else), you would probably be inclined to deal with validation in a different way. For example, a traditional jstl view resolver would nicely work with a contraption that uses Errors, while a jackson resolver would probably work nicer with a combination of #ResponseBody and some filter that catches errors and puts them in a predefined error part of the response object.
In one of our previous projects, we had huge forms with very complex logic which meant a lot of validating code. So we used a third kind of solution. For every controller, we autowired a helper class.
Example:
myview <-> MyController <- MyService <- MyDAO
^
|
MyHelper
Controllers handled the view resolving.
Services handled mapping from dto-s to model objects for view and vice versa,
DAO-s handled database transactions and,
Helpers handled everything else including validation.
If now someone would have wanted to change the frontend from web to something else, it would have been a lot easier and at the same time, we didn't over-bloat the service implementation classes.
I have design issue when implement 1 simple web application.
I use struts2 web controller, spring’s IOC and Hibernate as persist layer.
Because this web application is very simple at begging. So I only have 2 layers:
1 DAO layer which used to access database. Almost every table have related DAO.
2 Action layer. User struts2.
I am satisfy with this architecture because can quickly implement my web application.
As project become bigger, I found the action layer become big and complex, and very hard to re-use.
I try to create service layer, to solve complex business logic is good, but my application still have a lot of simply logic. E.g: Load 1 object, save 1 object, and get collection by some condition and display it to webpage. If give each simple DB access method have corresponding service method. Still cost a lot of effort. How can solve this issue?
And I think, if service layer existing, direct call DAO layer still not good design for my application.
Is any good solution for this kind of small web application?
When planing the different layers in a web application it is good practice to explicitly protect attributes and associations in your model from being manipulated without providing an identity context.
This is something that should neither be done in the DAO layer nor in the Controller. You should wrap your DAO layer in a service layer and have the controller only talk to the services not the DAO directly.
Protecting your model against unwanted manipulation means that you for instance adapt the amount of information passed in a data structure between Controller and Service to the actual operation that you want to perform.
For instance: adding or removing an element from a collection is an explicit operation in the service, it does not happen implicitly by manipulating a collection as a member of a DAO object and passing that DAO back into the service.
Instead your service may look like this:
+ getAllCompanies(): CompanyType[*]
+ getAllEmployeesOfCompany(c: CompanyType) : EmployeeType[*]
+ addEmployeeToCompany(e: EmployeeType, c: CompanyType)
+ removeEmployeeFromCompany(e: EmployeeType, c: CompanyType)
The additional benefit of such an architecture is that the service layer serves as boundary for your transactions. Using the methods of your controller as boundary for your transactions is in fact a very bad habbit. You could even call it an anti-pattern. Why? Because for instance it would mean that when your client hangs up it would roll back your transaction. That is clearly unwanted in 99% of the cases.
As #mwhs commented, Apache Isis provides plenty of guidance on layering your app. To figure out whether it fits your requirements, you could run through this tutorial I presented at a recent conference.