Using Spring Boot, I am trying to implement a REST controller, which can handle a GET request asking to return a BLOB object from my database.
Googling around a little bit, and putting pieces together, I have created the following code snippet:
@GetMapping("student/pic/studentId")
public void getProfilePicture(@PathVariable Long studentId, HttpServletResponse response) throws IOException {
    Optional<ProfilePicture> profilePicture;
    profilePicture = profilePictureService.getProfilePictureByStudentId(studentId);
    if (profilePicture.isPresent()) {
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(profilePicture.get().getPicture());
        outputStream.close();
    }
}
I am sending the GET request using VanillaJS and the fetch-API:
async function downloadPicture(profilePic, studentId) {
  const url = "http://localhost:8080/student/pic/" + studentId;
  const response = await fetch(url);
  const responseBlob = await response.blob();
  if (responseBlob.size > 0) {
    profilePic.src = URL.createObjectURL(responseBlob);
  } 
}
Somehow, this works. That's great, but now I would like to understand the usage of HttpServletResponse in this context, which I am not familiar with. It seems to me that the fetch-API makes use of HttpServletResponse (maybe even creates it), since I am not creating this object or do anything with it.
What is very strange to me is that the return-type of my controller method getProfilePicture() is void, and still I am sending a response, which is most definitely not void.
Also, if the profilePicture was not found in my database, for example due to a non-existing studentId being passed, my controller-method does not do anything. But still, I am getting a response code of 200. That's why I have added the responseBlob.size > 0 part in my Javascript to check for a positive response.
Can someone explain this magic to me, please?