Is your feature request related to a problem? Please describe. Our spring-cloud-openfeign clients have a default configuration in a starter. Only one showed for example.
feign.client.config.default.default-request-headers.accept=application/json
In some rare cases we implement specific clients that need different values. (for example purpose)
feign.client.config.specific-client.default-request-headers.accept=application/xml
Unfortunately FeignClientFactoryBean.addDefaultRequestHeaders() (version 3.1.2) lines 326 to 328 contain:
if (!headers.containsKey(key)) {
requestTemplate.header(key, defaultRequestHeaders.get(key));
}
specific-client config always passes after default client config, therefore the accept header value is never application/xml.
Describe the solution you'd like It would be nice (and backward compatible) if there was a config property to allow for default config to be applied after specific ones if enabled. Something like:
feign.client.config.apply-default-after=true
with the default value being false.
Describe alternatives you've considered We are still trying to figure out a way to override.
Additional context spring-cloud-openfeign version 3.1.2
Comment From: OlgaMaciaszek
Hello, @pgehl The model where client-specific config overrides default config has been adopted on purpose and is consistent throughout the Spring Cloud projects wherever applicable. We're not planning on changing it. Allowing changing the override direction would introduce inconsistency and would be quite messy and possibly cause maintenance issues.
Comment From: pgehl
Hello @OlgaMaciaszek, Thank you for the reply. Our issue is that the client specific config does not override the default config.
Comment From: fengyj
have the same issue.
Hi @OlgaMaciaszek, isn't it a bug? it doesn't make sense that the config of a particular service cannot override the default one.
Hi, @pgehl , have you resolved this issue finally? Thanks.
Comment From: fengyj
if (properties != null && inheritParentContext) {
if (properties.isDefaultToProperties()) {
configureUsingConfiguration(context, builder);
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(contextId), builder);
}
else {
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), builder);
configureUsingProperties(properties.getConfig().get(contextId), builder);
configureUsingConfiguration(context, builder);
}
}
private void addDefaultRequestHeaders(FeignClientProperties.FeignClientConfiguration config,
Feign.Builder builder) {
Map<String, Collection<String>> defaultRequestHeaders = config.getDefaultRequestHeaders();
if (Objects.nonNull(defaultRequestHeaders)) {
builder.requestInterceptor(requestTemplate -> {
Map<String, Collection<String>> headers = requestTemplate.headers();
defaultRequestHeaders.keySet().forEach(key -> {
if (!headers.containsKey(key)) {
requestTemplate.header(key, defaultRequestHeaders.get(key));
}
});
});
}
}
according to this code, the default config is used to set the header first, then the config of the particular service.
Comment From: OlgaMaciaszek
@pgehl @fengyj It should override. Please provide a minimal, complete, verifiable example that reproduces the issue - preferably as a link to a repo with a small executable app or tests.
Comment From: fengyj
hi @OlgaMaciaszek, thanks for the replying. I've uploaded a sample project here, https://github.com/fengyj/feigndemo/tree/master. there are two unit tests, one is using the config without the default config, and another one with the default config and overrides the default header value in the particular client config. You will see the second one is failed with the 406 Not Acceptable error.
// without the default config
@SpringBootTest
@EnableFeignClients(basePackages = "me.fengyj.feigndemo")
class YahooFinancialServiceTest {
@Autowired
private YahooFinancialService svc;
@Test
public void test_getHistoryPrice() {
var response = svc.getHistoryPrices("600036.SS");
Assertions.assertNotNull(response);
Assertions.assertTrue(response.startsWith("Date,Open,High,Low,Close,Adj Close,Volume\n"));
}
}
// with the default config
@SpringBootTest
@EnableFeignClients(basePackages = "me.fengyj.feigndemo")
@ActiveProfiles("defaultconfig")
class YahooFinancialServiceDefaultConfigTest {
@Autowired
private YahooFinancialService svc;
@Test
public void test_getHistoryPrice() {
var response = svc.getHistoryPrices("600036.SS");
Assertions.assertNotNull(response);
Assertions.assertTrue(response.startsWith("Date,Open,High,Low,Close,Adj Close,Volume\n"));
}
}
Comment From: OlgaMaciaszek
Thanks, @pgehl. Was able to reproduce it. Will provide a fix.