How to generate Java client proxy for RESTful service implemented with Spring?
Asked Answered
V

6

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

Ventris answered 12/5, 2013 at 21:23 Comment(5)
have you found any solution ?Araminta
Personally, I find Spring MVC test framework is the right tool. Testing in RESTful way can eliminate a lot of surprises. See docs.spring.io/spring-framework/docs/current/…Plumbery
What should you proxy do exactly ? If you are looking for another implementation of the REST protocol, there is also the cxf project.Sibley
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.Ventris
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 pointParticiple
A
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.

Acrylyl answered 18/2, 2016 at 17:58 Comment(2)
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.Ventris
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 :)Acrylyl
O
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.

Otoole answered 27/11, 2014 at 15:6 Comment(6)
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.Ventris
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...)Theis
@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.Otoole
@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?Otoole
@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.Ventris
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.Ventris
I
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.

Imaret answered 25/11, 2015 at 12:25 Comment(0)
V
1

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

Ventris answered 25/10, 2017 at 22:5 Comment(0)
M
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;
More answered 17/3, 2019 at 22:41 Comment(0)
D
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)
Derouen answered 6/11, 2021 at 20:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.