In spring boot application, I have two services: GroupService and UserService.There is also respective models classes, Group and User as well as the repositories. I am exposing two Rest endpoints, one for user and one for group. Now, I have an endpoint which adds the given user to a given group something like below, forget about the possible null checks and other issues at the moment.
@PostMapping(path="groups/{group-id}/add/{user-id}")
public ResponseEntity<Group> setUserGroup(@PathVariable(value="group-id")Long groupId, @PathVariable(value="user-id")Long userId)
{ Group group=groupService.findById(groupId);
group.addUser(userService.findById(userId));
return new ResponseEntity<Group>(groupService.save(group),HttpStatus.OK);
}
Now, the question is, what is the best practice to handle a scenario like that. Is not it good to handle the logic in Group service by injecting user service on it, rather than handling it in rest endpoint? In that case, the group service will be dependent on user service, but at least the logic can be reused if (lets imagine such a case) multiple rest endpoints require it.
The current implementation has an advantage as the services does not become dependent on each other. But, if we have complex logic, and lets say we have complex transactions, then definitely rest endpoint is not the right place for handling it. Please help me to understand which approach I should use, and what is the industry best practice.
It seems we have typical 3-tier architecture here!
If your classes "GroupService" and "UserServise" contains methods for direct storage manipulation(e.g create/read/update/delete/find by/etc.), they should not logically belong to service layer. Such classes belong to persistence layer and should be named like GroupRepository or GroupDao (DAO - Data Access Object).
Repository may be implemented manually, but popular way is to use Spring Data interfaces. I strongly recommend to check http://projects.spring.io/spring-data/#quick-start
In your case I see the following picture:
@Component
GroupRepository {
// Manually implemented DAO, but more simple way is Spring Data
...
}
@Component
UserRepository {
// Manually implemented DAO
...
}
@Service
ManagementService {
@Autowire
private UserRepositoty userRepository;
@Autowire
private GroupRepository groupRepository;
@Transactional
public Group addUserToGroup (Long groupId, Long userId) {
Group group=groupRepository.findById(groupId); group.addUser(userRepository.findById(userId));
return groupRepository.save(group);
}
}
@Controller
ManagementController {
@Autowire
private ManagementService managementService;
@PostMapping(...)
public ResponseEntity<Group> setUserGroup(@PathVariable Long groupId, @PathVariable Long userId) {
return new ResponseEntity<Group>(managementService.addUserToGroup(groupId, userId),HttpStatus.OK);
}
}
See https://www.petrikainulainen.net/software-development/design/understanding-spring-web-application-architecture-the-classic-way/
P.S. One remark regard usage of ResponseEntity: it is not mandatory in most cases, the simplified code below. Magic is behind RestController annotation. https://spring.io/guides/gs/rest-service/
@RestController
ManagementController {
@Autowire
private ManagementService managementService;
@PostMapping(...)
public Group setUserGroup(@PathVariable Long groupId, @PathVariable Long userId) {
return managementService.addUserToGroup(groupId, userId);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With