user3619911
user3619911

Reputation: 117

What are the best practices to handler or throw exceptions in a Spring Boot application?

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

Answers (4)

k13i
k13i

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

Pijotrek
Pijotrek

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 calls DAO class (extending JPARepository)

@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

kashish verma
kashish verma

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

2.) Spring Boot Tutorial

Upvotes: 0

Nitin Dhomse
Nitin Dhomse

Reputation: 2602

One of best way or what I do is,

  1. Check data / parameters for valid data( e.g Null check sometime manually using if statement).
  2. Checking data / parameters for size (like file size)
  3. checking data or parameters for valid range also data type, do typecasting if not in valid type (like String, Long, Integer etc).
  4. Raise a message and return to that API, if the data / parameters are not valid before system raise an exception

Upvotes: 0

Related Questions