Spring-cloud-netflix: Feign does not support @PathVariable for path at @FeignClient

Created on 29 Oct 2017  路  7Comments  路  Source: spring-cloud/spring-cloud-netflix

Base interface:

public interface SomeEndpoint {
    @RequestMapping(method = RequestMethod.GET, value = "/check")
    void check(@PathVariable("resource") String resource);
}

Feign client:

@FeignClient(value = "some-service", path = "/api/{resource}")
public interface SomeClient extends SomeEndpoint {
}

Usage example:

public class SomeTest {
    private final SomeClient someClient;

    @Autowired
    public SomeTest(SomeClient client) {
        this.someClient = someClient;
    }

    public void test() {
        someClient.check("hello");
    }
}

Output:

Exception in thread "main" java.lang.IllegalArgumentException: Illegal character in path at index 24: http://some-service/api/{resource}/check
 at java.net.URI.create(URI.java:852)
  at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:56)
  at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97)
  at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)
  at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
  at com.sun.proxy.$Proxy74.upload(Unknown Source)
  at SomeTest.test()
  ...
Caused by: java.net.URISyntaxException: Illegal character in path at index 24: http://some-service/api/{resourse}/check
  at java.net.URI$Parser.fail(URI.java:2848)
  at java.net.URI$Parser.checkChars(URI.java:3021)
  at java.net.URI$Parser.parseHierarchical(URI.java:3105)
  at java.net.URI$Parser.parse(URI.java:3053)
  at java.net.URI.<init>(URI.java:588)
  at java.net.URI.create(URI.java:850)
  ... 7 more

All 7 comments

Curious to know if this only occurs when using a sub interface?

I'm facing a similar issue as well. However I sub-classed the controller instead of the feign client.

Example code but should be similar.

@FeignClient("SomeService")
public interface FeignClient {
  @RequestMapping(path = "/{id}", method = RequestMethod.GET)
  getId(@PathVariable("id") long id)
}
public class BaseController {
  @Autowired
  FeignClient client;

  @RequestMapping(path = "/{id}", method = RequestMethod.GET)
  public String getId(@PathVariable("id") long id) {
    client.getId(id);
  }
}

@RequestController
@RequestMapping("/api")
public class Controller extends BaseController {
  @Override
  public String getId(@PathVariable("id") long id) {
    super.get(id);
  }
}



md5-4b99a47685bbe372dc176b2e59bda197



Caused by: java.lang.IllegalArgumentException: Illegal character in path at index 19: http://SomeService/{id}
 at java.net.URI.create(URI.java:852)
 at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:56)
 at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97)
 at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)
 at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108)
 at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:301)
 at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:297)
 at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)
 ... 28 common frames omitted



md5-90980cdc11fba8b27c8b25bfe05a00f0



@Override
  public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);

I guess I dont see the point in doing that. Why wouldnt Controller just use FeignClient directly?

The use case here is that we're in the midst of transitioning our v1 APIs to v2 APIs. The above code lies in our gateway. Extending the old controller would allow us to retain all our v1 APIs while selectively route certain routes to the v2 APIs. In Controller, we would call super, then call FeignClientV2, and compare the results. This is to ensure that the v2 APIs are backward compatible with the old responses and that we don't break anything.

The fuller code probably looks like this.

@RequestController
@RequestMapping("/api")
public class Controller extends BaseController {
  @Autowired
  FeignClientV2 clientV2;

  @Override
  public String getId(@PathVariable("id") long id) {
    String oldResponse = super.get(id); // exception is thrown here
    String newResponse = clientV2.get(id);
    if (!oldResponse.equals(newResponse)) {
      // do some logging
    }
    return oldResponse;
  }
}

Sorry for not giving the full use case previously because it seems irrelevant to the issue at hand.
Is this supposed to happen when sub-classing the controller?
off-topic: Is there a better way to achieve what I want?

Doesn't seem relevant to the feign issue

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Hello Folks,
Today i faced the same issue and i found the solution.
The problem with my code snippet was,have passed null value for ID attribute.
public String getId(@PathVariable("id") long id)
so while making the feign request, url path variable attribute is not getting replaced with pathVariable(ID) rather then replacing the actual id value.
When id as null -> http://SomeService/{id}
When id as proper value -> id = 123 ->http://SomeService/123.
Correct me, if am wrong @spencergibb
Thanks

Was this page helpful?
0 / 5 - 0 ratings