Search code examples
springspring-mvccompletable-futurespring-cloud-contract

CompletableFuture<ResponseEntity> Status Code Expectations


So, I have created a Controller within which I have a POST endpoint like so:

@PostMapping("/foo/{some-field}")
public CompletableFuture<ResponseEntity> foo() {
    //Do some operations...
    ...
    if(doesNotExist({some-field})) {
        return CompletableFuture.completedFuture(ResponseEntity.notFound().build());
    }
    return CompletableFuture.completedFuture(ResponseEntity.ok().build());
}

Now I would expect that if doesNotExist({some-field}) == true, I'd be prompted with a NOT_FOUND status. I however end up with a OK status every time around.

Are my expectations wrong in regards to how the ResponseEntity is returned? Any suggestions how to get the NOT_FOUND status if doesNotExist({some-field}) == true would be much appreciated.

Edit/Update

From the comments I assume my initial question was a little to light, so let me explain when I see this failing, as it seems that my assumption of what the ResponseEntity.HttpStatus would be is correct.

I have made small adjustments to the code block above. The situation where I receive an unexpected status is when I try to test the NOT_FOUND situation through Spring Cloud Contracts.

An example of the contract looks as follows:

Contract.make {
  request {
    method 'POST'
    url "/foo/SomeNoneExistingField"
    body("{}")
    headers {
      contentType applicationJson()
    }
  }
  response {
    status HttpStatus.NOT_FOUND.value()
  }
}

So the {some-field} in this contract is set to a field which ensure that doesNotExist({some-field}) == true. I see it end up in this block if I am debugging my code as well. Nonetheless, the Spring Cloud Contract test status that the response.status == OK i.o. NOT_FOUND.

Might I be using Spring Cloud Contracts incorrectly if my assumption on the HttpStatus returned from a CompletableFuture is correct? Any help/advice is (again) much appreciated.


Solution

  • Ok, I figured out the issue I was experiencing. Credits to @Marcin Grzejszczak for putting me on the right track in regards to configuration.

    What I was missing from my contracts to be able to handle async results, like a CompletableFuture, was that I needed to add async() to my result.

    Thus, a contract like so:

    Contract.make {
      request {
        method 'POST'
        url "/foo/SomeNoneExistingField"
        body("{}")
        headers {
          contentType applicationJson()
        }
      }
      response {
        status HttpStatus.NOT_FOUND.value()
        async() // <---- This was it!
      }
    }
    

    Did the trick.