Chapter 2 · Practice 3 of 4
Keep controllers thin and business logic in services
Why it matters
A controller's job is HTTP: read the request, validate it, call a service and map the result to a response. When business rules live in controllers, they cannot be reused by a scheduled job or a message listener, and tests need a web layer to reach them.
- Controllers: map requests and responses, run validation, set status codes.
- Services: business rules and transaction boundaries.
- Repositories: data access only.
A quick test: could you call this logic from a command-line runner without faking an HTTP request? If not, it belongs in a service.
Do
- Put
@Transactionalon service methods, not controllers - Map entities to response DTOs in one place
- Keep controller methods to a few lines