14

We use Spring to implement REST controller, for example:

@Controller
@RequestMapping("/myservice") 
public class MyController {
    @RequestMapping(value = "foo", method = RequestMethod.GET)
    public @ResponseBody string foo() {...}
}

I can call this service using spring RestTemplate, and it works fine, but I would prefer to invoke it using a proxy, instead of typeless invocation using string url:

// client code:
MyController proxy = getProxy("baseUrl", MyController.class);
String results = proxy.foo();

So the input to proxy generation is java interface with annotations describing REST details. I read this article and it looks like all types of remote calls do have proxies, and all I need for REST is something like RestProxyFactoryBean, that would take my REST java interface and return type-safe proxy that uses RestTemplate as implementation.

The closest solution I found is JBoss RESTEasy.

But it seems to use different set of annotations, so I am not sure it will work with annotations I already have: @Controller, @RequestMapping. Are there other options, or RESTEasy is the only one? Note, I am spring newbie so some obvious spring things are pretty new to me.

Thank you.
Dima

Dima
  • 699
  • 1
  • 6
  • 18
  • have you found any solution ? – Suraj Oct 31 '13 at 16:49
  • Personally, I find Spring MVC test framework is the right tool. Testing in RESTful way can eliminate a lot of surprises. See http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/testing.html#spring-mvc-test-framework – Christopher Yang Nov 13 '14 at 17:48
  • What should you proxy do exactly ? If you are looking for another implementation of the REST protocol, there is also the cxf project. – Patouche Nov 16 '14 at 08:29
  • I ended up writing my own code generator: rest api is written as java interface with annotations, proxy generator reflects it and generates client proxy class implementing the interface. Server side implementation has to be written, as usually. – Dima Dec 05 '15 at 12:50
  • this is actually an interesting thing. from my point of view it is important to have the proxy in order to make sure URLs and parameter names are not hardcoded. so version upgrades does not need find and replaces. The proxy may be opinionated and use `RestTemplate` on its own but thats not the point – mohamnag Jun 12 '18 at 08:12

6 Answers6

3

You can try Feign by Netflix, a lightweight proxy-based REST client. It works declaratively through annotations, and it's used by Spring Cloud projects to interact with Netflix Eureka.

pcan
  • 893
  • 11
  • 24
  • I wonder if Feign was production-ready in 2013 when I needed it. Initial commit for Feign was in the spring of 2012, and first issue logged in summer 2013. – Dima Feb 19 '16 at 19:22
  • Hmm.. I cannot tell if Feign was production-ready in 2013, but for sure I know that many already existing Netflix projects were open sourced in that period.. maybe Feign was one of them? but I'm not sure of this of course :) – pcan Feb 21 '16 at 12:41
1

One of the reasons the REST paradigm was invented was because expirience with other remoting technologies (RMI, CORBA, SOAP) shows us that often, the proxy-based approach creates more problems than it solves.

Theoretically, a proxy makes the fact that a function call is remote transparent to its users, so they can use the function exactly the same way as if it were a local function call.

In practice however this promise cannot be fulfilled, because remote function calls simply have other properties than local calls. Network outages, congestion, timeouts, load problems to name just a few. If you choose to ignore all these things that can go wrong with remote calls, your code probably won't be very stable.

TL;DR: You probably shouldn't work with a proxy, it's not state of the art any more. Just use RestTemplate.

Bastian Voigt
  • 5,311
  • 6
  • 47
  • 65
  • 3
    You concerns about remoteness nature of proxy call can be addressed with additional parameters like timeout, retry count, network error handlers, naming of the remote methods. I am trying to solve problem of simple and stupid mismatch between client and server (happens a lot), and using power of compiler to catch my typos. – Dima Dec 05 '15 at 12:59
  • This seems to be the conventional wisdom, but i struggle to how constructing http calls eliminates these issues. Aren't you still catching the same exceptions whether you use a proxy client or RestTemplate? I would think it would be pretty easy for a developer to see an interface filled with REST annotations and realize that's a remote call. It just feels like the reasons against proxies are somewhat vague while the pain of not using them is very concrete (boilerplate code, potential divergence from the server version, procedural over declarative coding, etc...) – Michael Haefele Nov 29 '17 at 19:00
  • @MichaelHaefele: Yes of course the problems are still the same, that's not the point. But when I read the code, it's obvious to me that these problems can occur, while a proxy hides the fact from the reader. – Bastian Voigt Nov 30 '17 at 12:53
  • @Dima: If you add additional technical parameters to your proxy it's fine, that makes the code more readable and developers won't be that surprised when they get a timeout. However, if you do that, then why do you want a proxy in the first place? The whole point of using a proxy is to hide the "remoteness" or your function call, isn't it? – Bastian Voigt Nov 30 '17 at 12:56
  • 1
    @Bastian Voigt, the point of generated proxies is to hide complexity of building and parsing json, dealing with HTTP client settings, etc. But its biggest benefit (IMO) is converting some runtime errors into compile errors because of strongly typed nature of proxy. Yes, proxy can hide remote nature of the call, but it's not the goal. In fact modern proxies (mine was not) use things like Future to deal with network slowness, but still making it easy to use and protecting client from some protocol changes. – Dima Dec 01 '17 at 15:13
  • Yet another reason to use generated proxies is to reduce amount of hand-written code. I prefer to spend my time writing generator (if it's not already available) and interface with annotations than copy-paste the same boiler-plate code N times with slight modifications and chase copy-paste bugs. – Dima Dec 01 '17 at 15:25
1

Here is a project trying to generate runtime proxies from the controller annotations (using RestTemplate in the background to handle proxy calls): spring-rest-proxy-client Very early in implementation though.

NagyI
  • 5,907
  • 8
  • 55
  • 83
1

This seems to do it: https://swagger.io/swagger-codegen/, and swagger has many other nice things for REST API.

Dima
  • 699
  • 1
  • 6
  • 18
0

Have a look at https://github.com/ggeorgovassilis/spring-rest-invoker. All you need is to register FactoryBean:

@Configuration
public class MyConfiguration {

    @Bean
    SpringRestInvokerProxyFactoryBean BankService() {
        SpringRestInvokerProxyFactoryBean proxyFactory = new SpringRestInvokerProxyFactoryBean();
        proxyFactory.setBaseUrl("http://localhost/bankservice");
        proxyFactory.setRemoteServiceInterfaceClass(BankService.class);
        return proxyFactory;
    }

and after that you can autowire the interface class:

@Autowired
BookService bookService;
Ilya Serbis
  • 21,149
  • 6
  • 87
  • 74
0

I also ended up making my own library for this. I wanted something that is as small as possible, adds only itself to classpath and no transitive dependencies.

A client is created like:

final StoreApi storeApi = SpringRestTemplateClientBuilder
  .create(StoreApi.class)
  .setRestTemplate(restTemplate)
  .setUrl(this.getMockUrl())
  .build();

And rest-requests will be performed when invoking the methods:

storeApi.deleteOrder(1234L);

The is supports both method signatures:

  • ResponseEntity<X> deleteOrder(Long)
  • X deleteOrder(Long)
Tomas Bjerre
  • 3,270
  • 22
  • 27