2

I have a controller that should return 204-No Content when no element exists in the list returned by the repository. In Spring when I return an empty list, the response status is 200-OK. I found a way to solve this setting my controller to return a Response Entity, but there is another way of doing this? I don't want to throw a exception, since a empty list in my use case makes sense, and can't use @ResponseStatus because in the use case the list can have elements too and so I need to return 200-OK and the list.

I solved using this approach, but I want to return a List<Parcela> in my controller and 204-No content

@GetMapping(path = "/contratos/{numeroContrato}/parcelas", params = "status")
ResponseEntity<List<Parcela>> filtrarParcelasPorStatus(@PathVariable String documento,
        @PathVariable String numeroContrato, @RequestParam StatusParcela status) {
    try {
        List<Parcela> parcelasFiltradas = veiculosUsecase.filtrarParcelasPorStatus(documento, numeroContrato,
                status);
        if (parcelasFiltradas.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<>(parcelasFiltradas, HttpStatus.OK);
    }
    catch (ParcelasNaoEncontradasException e) {
        throw new NotFoundException(
                "Nao e possivel listar as parcelas porque nao foi encontrado o contrato para o numero de contrato e cliente informado",
                "Nao e possivel listar as parcelas porque nao foi encontrado o contrato para o numero de contrato e cliente informado",
                HttpStatus.NOT_FOUND.toString(), "External - Veiculos API");
    }
}
ghn1712
  • 105
  • 1
  • 3
  • 15
  • please share the way used with a sample code. – davidxxx Aug 08 '18 at 17:42
  • 1
    What exactly is the issue? Those looks fine to me. – Darren Forsythe Aug 08 '18 at 17:47
  • Yes, it works fine, but I want to not return a `Response Entity`, just a `List`, and don't know if there's a way to do it. – ghn1712 Aug 08 '18 at 17:49
  • 1
    No, there's no easier way, you can start throwing exceptions left right and center but that is not good design. Your controller will be wrapping the returned entitiy irregardless if you return a response entity or not. This is the perfect way to do it. – Darren Forsythe Aug 08 '18 at 17:51
  • On the other hand, it makes no sense wanting to return two different types of objects from the same method, also, the controller function is going to be called by Spring, so why the return type it matters so much? – rekiem87 Aug 08 '18 at 17:52
  • You're not returning different types. You're just wrapping the returned object before Spring does it for you. Spring will wrap the returned object irregardless in a response entity. This gives you control over items like HTTP status, which is exactly what you want – Darren Forsythe Aug 08 '18 at 17:54
  • I was referring to his intention to return a 204 response and an Entity in the same method, I totally agree with you. There must be the ResponseEntity, the only thing that can be changed is using the static methods: return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World"); but in the end will be the same – rekiem87 Aug 08 '18 at 17:58
  • @rekiem87 It's not two different types, I'm always returning a `List`, but if the `List` is empty, I think makes more sense to return 204 instead of 200. And I want the return type to be a List because in all other controller methods I'm not using `Response Entity`, and I don't want to change all other return methods if there's another way. – ghn1712 Aug 08 '18 at 17:58
  • YOu're over thinking it. This is exactly how it should be handled. It doesn't matter if the other methods return just a basic object or a response entitiy callers to your API will get items like status codes, headers etc. Additionally why would you have to change the other methods? – Darren Forsythe Aug 08 '18 at 18:00
  • @DarrenForsythe Yes, I agree with you. I just wanted to be sure if there's another way, I know that my controller is used just by Spring (and I don't think another object or framework will use this method) but I saw something with `@ControllerAdvice` for exceptions, I just wanted to check if there's something like this to check for empty lists or if there's something Spring provides – ghn1712 Aug 08 '18 at 18:04
  • 204 as empty response is more used for things like "save the thing fine, that's all you need to know", you can argue that the empty list could be used also, but maybe for someone the correct thing is to return a 404, since no results were found, spring is about convention over configuration, since this can be view from many necessities, they provide a default and general response (200) and provides you an easy way to change it if does not correspond with your necessities – rekiem87 Aug 08 '18 at 18:04
  • 1
    Maybe could be an option in spring could be used to set a "default behavior for empty lists", sadly this does not exist today, but you could create an issue and see if more people and the spring team are interested https://github.com/spring-projects/spring-boot – rekiem87 Aug 08 '18 at 18:08
  • @rekiem87 I don't think it should be a 404 because in this request the client is filtering by status the entity, so a empty list means something, maybe a 200 with an empty JSON array can be a better approach , instead of 204 or 404 – ghn1712 Aug 08 '18 at 18:16
  • 1
    And about why I want to return just a List and Spring wrap this to me, it's because returning a `ResponseEntity` i have to check if the list is empty or not, but using the `@ControllerAdvice` i can just return the List – ghn1712 Aug 08 '18 at 18:56
  • You could always make a general method that receives the list with generics and return the ResponseEntity with the list or the 204 so you do not repeat the empty validation return Util.listOr204(myList); but yeah, you still need to do the extra work – rekiem87 Aug 08 '18 at 19:45
  • @rekiem87 Yeah, I was saying that in the controller I don't need to do this extra work, with the solution that I found I can do this in the `@ControllerAdvice` and still return a List, instead of return a ResponseEntity and completely couple my controller to Spring – ghn1712 Aug 08 '18 at 20:06
  • Yes, in one side manual checking for something repetitive, on the other use exceptions for things that are part of the normal flow... i would use ResponseEntity to avoid the exception overhead and because the "correct" thing to do is to not use exceptions for normal flows, but, always, programming is an art, so, i do not think is wrong doing otherwise – rekiem87 Aug 08 '18 at 20:16
  • 1
    @rekiem87 please check the solution I [proposed](https://stackoverflow.com/a/51753688/9091513) in the answers, it doesn't use exceptions, so I agree with you about exceptions in normal flows – ghn1712 Aug 08 '18 at 20:22

3 Answers3

5

Returning

return new ResponseEntity<>(HttpStatus.NO_CONTENT);

will return 204-No content. This is the right way to do it. Works for me just fine as well

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
  • 2
    It is exactly what he is doing, he is asking for other way to do it so he can just set his return type to List and not ResponseEntity, but we all agree this is the correct way and I do not understand what he did not like about it – rekiem87 Aug 08 '18 at 17:59
  • Yes, he is already doing what is right. However he is asking if there is another way or this way is correct. My answer answers his question that the way he does it IS correct thus providing a valid and legitimate answer to his question – Michael Gantman Aug 08 '18 at 19:22
2

There are a few ways to return custom HTTP status code:

  1. Throw an exception and put an annotation on your custom exception

    @ResponseStatus(HttpStatus.NO_CONTENT)
    public class EmptyListException extends RuntimeException {}
    
  2. Be more organized and put the same thing into @ControllerAdvice

    @ControllerAdvice
    class GlobalControllerExceptionHandler {
        @ResponseStatus(HttpStatus.NO_CONTENT)
        @ExceptionHandler(EmptyListException.class)
        public void handleException() {}
    }
    
  3. Use your @ResponseEntity like you did.

    return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    

Although it makes more sense to use exceptions for error codes (4XX and 5XX). I used ResponseEntity at first as well, but you can see yourself how messy your controller become.

It may be a matter of taste, but I would recommend creating your "business" exceptions like EmptyListException, throwing them in your service layer and then handling them in the separate @ControllerAdvice. That way it will be easier to read and support.

ottercoder
  • 852
  • 1
  • 12
  • 31
  • I think this is a better approach, but I don't want to throw a exception, because a empty list is something that can happen frequently in my use case, so I think it's a normal condition and then I should not throw a exception. – ghn1712 Aug 08 '18 at 18:21
2

I researched a little more and found this, it's closer to what I was looking for, with this I don't need to check if the list is empty to return

ghn1712
  • 105
  • 1
  • 3
  • 15
  • 1
    Nice, that have all the advantages, none of the disadvantages , now this seems like a duplicated question – rekiem87 Aug 08 '18 at 20:35