With feign it was possible to easily map 404 exceptions to null via the dismiss404 functionality. It seems like, that there is no easy and convenient way to do that wie http interfaces and restclient.
My current workaround is to write my own implementation of the HttpExchangeAdapter
interface.
public class MyExchangeAdapter implements HttpExchangeAdapter {
private final HttpExchangeAdapter delegate;
public MyExchangeAdapter(HttpExchangeAdapter delegate) {
this.delegate = delegate;
}
public static HttpExchangeAdapter create(RestClient client) {
return new MyExchangeAdapter(RestClientAdapter.create(client));
}
@Override
public boolean supportsRequestAttributes() {
return delegate.supportsRequestAttributes();
}
@Override
public void exchange(HttpRequestValues requestValues) {
delegate.exchange(requestValues);
}
@Override
public HttpHeaders exchangeForHeaders(HttpRequestValues requestValues) {
return delegate.exchangeForHeaders(requestValues);
}
@Override
public <T> T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return exchangeForEntity(requestValues, bodyType)
.getBody();
}
@Override
public ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestValues) {
return delegate.exchangeForBodilessEntity(requestValues);
}
@Override
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
try {
return delegate.exchangeForEntity(requestValues, bodyType);
} catch (HttpClientErrorException.NotFound ex) {
return ResponseEntity.notFound().build();
}
}
}
and configure my client something like:
@Configuration
public class MyClientConfig {
@Bean
public MyClient myClient(RestClient.Builder restClientBuilder) {
var client = restClientBuilder
.defaultStatusHandler(this::isError, (request, response) -> {
})
.build();
var httpServiceProxyFactory = HttpServiceProxyFactory
.builderFor(MyExchangeAdapter.create(client))
.build();
return httpServiceProxyFactory.createClient(MyClient.class);
}
public boolean isError(HttpStatusCode statusCode) {
return statusCode.isError() && statusCode != HttpStatus.NOT_FOUND;
}
}
Am i missing a more elegant and easy way or do you plan to provide some dismiss404 mechanism?
Thanks!
Comment From: simonbasle
@floriandreher do you actually need the MyExchangeAdapter
class at all? I just tried with the default status handler and it seemed to work.
Comment From: floriandreher
Hi @simonbasle, i've created a small test. It seems like my return object is not null, but it's content is null. Shouldn't the whole object be null? I think, that this was the feign behaviour
Thanks! demo.zip
Comment From: simonbasle
yeah I see what you mean, this is indeed not ideal because if the 404 response contains a body, having the empty defaultStatusHandler
doesn't help as we'll ultimately attempt to decode said body into a T
, which is likely to fail or produce an undesirable result.
I need to discuss this with the team, but here is a proposal: what would you think about declaring the interface method to return Optional<T>
and the framework would then dismiss a 404 response in that case?
Comment From: floriandreher
Your proposal would work for me :)
Comment From: simonbasle
after further discussion within the team, we feel my earlier proposal could introduce further inconsistencies and potential side effects, compared to the approach you yourself took which is rather straightforward after all, without the need for risky changes from a framework perspective.