Java REST – Check Resource Existence Before Database Insertion or Handle DAO Exception

exceptionsjavarest

I have two paths:

  • /students
  • /students/{id}/addresses

…with the following behavior:

POST to /students201 Created (if successfully created the Student)
POST to /students/{id}/addresses201 Created (if successfully created the Address under the requested user)
Now, imagine a situation where the client POST to /students/12/addresses, but there's no Student with id = 12.

How should I handle this scenario?

Should I insert without any check and wait for DAO to throw the Exceptions or, before inserting, I should check for Student's existance?

1st option:

StudentController.java

@Autowired
private AddressService addressService;

@PostMapping("/students/{id}/addresses")
public ResponseEntity<?> handleRequestOfCreateAddressToStudent(@PathVariable("id") Long studentId, @RequestBody Address address) {
    address.setStudent(new Student(studentId));
    Address createdAddress = addressService.saveAddress(address);

    URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").build(createdAddress.getId());
    return ResponseEntity.created(location).build();
}

AddressService.java

@Autowired
private AddressRepository addressRepository;

public Address saveAddress(Address address) {
    // omitted for brevity...
    return addressRepository.save(address);
}

This way, since I'm using Spring framework, the line return addressRepository.save(address); would throw a DataIntegrityViolationException, because the constraint is violated (there's no Student with such ID to bind with that Address). And, since I need to send the response to the client, I would have to translate the exception that is throwed.

2nd option:

StudentController.java

@Autowired
private StudentService studentService;

@Autowired
private AddressService addressService;

@PostMapping("/students/{id}/addresses")
public ResponseEntity<?> handleRequestOfCreateAddressToStudent(@PathVariable("id") Long studentId, @RequestBody Address address) throws StudentNotFoundException {
    Student student = studentService.findById(studentId);

    if(student == null)
        throw new StudentNotFoundException("message");

    address.setStudent(new Student(studentId));
    Address createdAddress = addressService.saveAddress(address);

    URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").build(createdAddress.getId());
    return ResponseEntity.created(location).build();
}

This way, I don't need to translate the Exception, as I already know that the Student does not exist so that I can throw a custom exception.

My thoughts in both approaches:

  1. Without checking, I do reduce the code and the number of times I
    trigger my database;
  2. Checking, I do know exactly why I'm unable to add the Address (the
    Student does not exist) and can throw a custom exception without
    having to translate it;

Which one is the best approach to this scenario?

Should I wait for the DAO to throw the Exception, or should I prevent it from throwing by checking if the Student exists?

Best Answer

You should never use exceptions as a flow-control device. Check for the existence of the Student first, then add the address. As you noted, this give you more control over the messaging you send, plus you keep all the logic in the same flow (as opposed to returning messages from both the main block and the exception handler).

Related Topic