Reputation: 117
I've developed a rest api using Spring Boot. In one of my service methods, I throw a ServletException
, in case a specific user is not found. I am wondering if that is the best way to do that, I mean, is that the right layer to thrown the exception?
Upvotes: 3
Views: 6788
Reputation: 4331
Creating a custom exception type is a better idea than using ServletException
.
In order to handle an exception you can use @ControllerAdvice
.
First create custom exception type:
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
Assuming that your controller and service look more or less like this:
@RestController
@RequestMapping("users")
class UserController {
private final UserService userService;
UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
List<String> users() {
return userService.getUsers();
}
}
@Service
class UserService {
List<String> getUsers() {
// ...
throw new UserNotFoundException("User not found");
}
}
You can handle you UserNotFoundException
using @ControllerAdvice
@ControllerAdvice
class CustomExceptionHandler {
@ExceptionHandler({UserNotFoundException.class})
public ResponseEntity<Object> handleUserNotFoundException(UserNotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND);
}
}
Upvotes: 10
Reputation: 3021
Throwing exception in your @Service
is okay. ServletException
is not super meaningful. What I would suggest is to create your own Exception class extending RuntimeException
and throw it.
So you would end up with something like that:
A Controller that only calls a service method (better not to have any logic here)
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUserById(@PathVariable("id") Long id) {
return userService.getById(id);
}
}
A
Service
class that callsDAO
class (extendingJPARepository
)
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public User getById(Long id) {
return userDAO.findById(id).orElseThrow(() -> new UserNotFoundException("No user with id = " + id + " found."));
}
}
DAO:
@Repository
public interface UserDAO extends JpaRepository<User, Long> {
}
note: it returns Optional<Object>
which is very convinient.
And finally your own
Exception
class.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
Note: @ResponseStatus
- it is going to return HTTP Status code 404 on throwing this exception.
This is imho a very clean and good way to develop your rest api.
Also take a look here: How to get spesific error instead of Internal Service Error . I answered a question providing information you might find useful
Upvotes: 0
Reputation: 61
I am assuming you are looking to catch all exceptions occured inside your application. Spring-Boot provides a Global Exception Handler to catch all the exceptions gracefully and return response according to the the specific Exception. It gives you flexibility to change the status codes, response data, headers accordingly. Few useful links to implement this feature is -
1.) Dzone
Upvotes: 0
Reputation: 2602
One of best way or what I do is,
Upvotes: 0