I'm evaluating Retrofit 2 for our project (Java-based Server Side application with microservices architecture, microservices interact via HTTP) and have a hard time to understand the following:
Documentation of OkHttpClient states that instance of OkHttpClient should better be shared for all HTTP Calls, so I conclude that it should be a singleton object in a microservice (for example a spring bean with scope Singleton).
When I generate a retrofit powered proxy, I use the following code:
Retrofit.Builder builder = new Retrofit.Builder();
Retrofit retrofit = builder
.baseUrl(baseUrl)
.client(okHttpClient) // reusing the same http client instance
.build();
retrofit.create(<class_of_my_interface_goes_here>);
So far so good, but now I would like to add some custom headers to the calls that will be executed on the proxy of my interface.
For example, assuming I have two interfaces:
interface RequiresAuthToken {
#GET(...)
Call<...> doSomething();
}
interface NoAuthTokenRequired {
#GET(...)
Call<...> doSomethingElse();
}
For the first Interface calls - I would like to pass an Authorization Header, but for the second service calls - I don't need this functionality
Of course, an obvious solution is to just add the token to the parameters but I don't really want to do this for each service, because it's an infra level stuff.
Authorization header is just an example, other examples can be adding headers for current client identifier that executes the request, tenant id for multi-tenant environment setups and so on.
In all the documents I've found so far, the recommendation is to use ok http client interceptors, but these are added when the ok http client is created (singleton instance)
new OkHttpClient.Builder()
.addInteceptor(...)
.build();
So my question is how to add interceptors at the call level?
I would like to do this at the infrastructure level of retrofit and not by altering the call in the applicative code
Related
I am using Spring RestTemplate for executing HTTP request from my application. There are several services we need to call, some on the internet and some on intranet, some fast and some slow. I have been instructed to configure custom settings for each service, basically, connection timeout, read timeout.
These setting will be extremely specific for example, the services hosted on intranet would have a timeout of ~2-5s while they provide an SLA of 1000ms for 99.9% of requests. While the other third party services with ~10-60s.
As these parameters can be set in the factory for the template only, i am creating a number of beans with different factories differing in timeouts only. Something like this:
#Bean
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setReadTimeout(20000);
factory.setConnectTimeout(5000);
RestTemplate restTemplate = new RestTemplate(factory);
}
I am afraid this will create a maintenance nightmare eventually. Can it be solved in a better ways?
PS: The application is a monolith calling various services.
You will have to create multiple RestTemplates and assign timeouts, connection pool size. Connection pool will improve the performance drastically
I have hard-coded the connection properties, you can pick it from application.properties file
#Configuration
class RestTemplateConfigs {
#Bean
public HttpClient httpClient() {
return HttpClientBuilder.create()
.setMaxConnPerRoute(200)
.setMaxConnTotal(50)
.setConnectionTimeToLive(10L, TimeUnit.SECONDS)
.build();
}
#Bean(name = "restTemplate1")
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
}
You can create multiple RestTemplates and Autowire it using Qualifier name.
Disclaimer: my answer suggests to work with another Http client than Rest Template - If you must use Rest template my answer would be irrelevant.
I dealt with a similar design issue and here is what I did. I wrote my own HttpClient class. It is much simpler in use then most known Http clients. This class could be used on its own or (and this is relevant for your case) it could be used as a parent class for a group of classes (implementing the same interface) where each class will be an Http client for specific Rest Service. On this class you can pre-set the target URL and all the parameters (such as read and connection timeouts etc). Once this class is preset, all you need to do is to invoke sendHttpRequestMethod(). Just to expand a bit - lets say you have a User Rest service with CRUD API implemented by particular URL calls with different HTTP methods and may be different URLs. (say in addition to create (POST) update (PUT) read (GET) and delete (DELETE) methods that are located at HTTP://www.myserver.com:8083/user say you will also have methods activate and deactivate (say both GET) at URLs HTTP://www.myserver.com:8083/user/activate/ and HTTP://www.myserver.com:8083/user/deactivate.
So, in this case, your Http client will set all required timeouts and other configurations and it will also have pre-set target URL HTTP://www.myserver.com:8083/user. and it will have six methods as mentioned above, where each one will simply invoke the parent class method sendHttpRequest(). Of course, for activate and deactivate methods you will need to append "activate" and "deactivate" suffixes for pre-set base URL. So, for each REST service, you can create a dedicated Http client with very minimal effort since the base class already does most of the job. In addition to it, I wrote a self-populating factory for any group of classes that implement the same interface. With that factory, all you will have to do is to write your additional Http client and the factory will detect it and will make it available on its own by predefined name or by the name of the class (based on your choice). All this worked so well for me, that I packaged it into Open Source library called MgntUtils and published it on Maven and Github (with source code and Javadoc. JavaDoc is available here). A detailed explanation on the Self-populating factory can be seen in Javadoc here. Also, the general article about the library can be found here and specific article about the idea and the implementation of self-populating Factory can be found here. Package com.mgnt.lifecycle.management.example in the source code contains a working example. I hope this helps.
Using parameterized construction of the RestTemplate bean solved my problem.
The bean is now configured as:
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RestTemplate getRestTemplate(String configParam){
int connectionTimeout; //get from config using configParam
int readTimeout; //get from config using configParam
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectionTimeout);
factory.setReadTimeout(readTimeout);
return new RestTemplate(factory);
}
Instead of #Autowiring this field, it can be injected in may be #PostConstruct method like depicted below. The dependent bean can do following:
#Autowire
BeanFactory beanFactory;
RestTemplate restTemplate;
#PostConstruct
public void init(){
restTemplate = beanFactory.getBean(RestTemplate.class, configParam);
}
Here you can have your bean with custom settings injected in restTemplate.
I am confused about how an infinite loop of feign calls might behave.
An example:
Assume I have 2 APIs, A & B.
if I call API A, which in turn calls API B via a feign HTTP call, which in turn calls API A again via feign, will it recognize this and break the call chain?
Quick flowchart of calls:
A -> B -> A -> B ... Repeat infinitely?
I have not tried this code, it is just an idea。
But I am assuming that spring-cloud-starter-feign will provide some methods to resolve this problem? Is this assumption correct?
#PostMapping(RestJsonPath.API_A)
ResponseEntity<byte[]> apiA();
#PostMapping(RestJsonPath.API_B)
ResponseEntity<byte[]> apiB();
Will it execute until it times out or hystrix will stop it?
TL;DR:
Feign will keep the connection open on the initial request from A to B until the pre-configured timeout kicks in. At this point, Feign will time out the request and if you have specified a Hystrix fallback, Spring will use your Hystrix fallback as the response.
Explanation:
spring-boot-starter-feign provides an abstraction layer for writing the HTTP request code. It will not handle potential loops or cycles in your code.
Here is an example spring boot feign client from their tutorials website for demonstration:
#FeignClient(value = "jplaceholder",
url = "https://jsonplaceholder.typicode.com/",
configuration = ClientConfiguration.class,
fallback = JSONPlaceHolderFallback.class)
public interface JSONPlaceHolderClient {
#RequestMapping(method = RequestMethod.GET, value = "/posts")
List<Post> getPosts();
#RequestMapping(method = RequestMethod.GET, value = "/posts/{postId}", produces = "application/json")
Post getPostById(#PathVariable("postId") Long postId);
}
Notice first that this is an interface - all the code is auto generated by Spring at startup time, and that code will make RESTful requests to the urls configured via the annotations. For instance, the 2nd request allows us to pass in a path variable, which Spring will ensure makes it on the URL path of the outbound request.
The important thing to stress here is that this interface is only responsible for the HTTP calls, not any potential loops. Logic using this interface (which I can inject to any other Spring Bean as I would any other Spring Bean), is up to you the developer.
Github repo where this example came from.
Spring Boot Docs on spring-boot-starter-openfeign.
Hope this helps you understand the purpose of the openfeign project, and helps you understand that it's up to you to deal with cycles and infinite loops in your application code.
As for Hystrix, that framework comes in to play (if it is enabled) only if one of these generated HTTP requests fails, whether it's a timeout, 4xx error, 5xx error, or a response deserialization error. You configure Hystrix, as a sensible default or fallback for when the HTTP request fails.
This is a decent tutorial on Hystrix.
Some points to call out is that a Hystrix fallback must implement your Feign client interface, and you must specify this class as your Hysterix fallback in the #FeignClient annotation. Spring and Hystrix will call your Hystrix class automatically if a Feign request fails.
It`s possible to register one filter in RestEasy that will works for any instance? Today I have a lot of services thats use one client
for example:
Client client = ClientBuilder.newClient();
WebTarget target = client.target(ulrBase);
ResteasyWebTarget rtarget = (ResteasyWebTarget) target;
this.servico = rtarget.proxy(UsuarioServiceClient.class);
but now I have to pass one header prop, so I create this:
public class AuthHeadersRequestFilter implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add("xx-Authorization", ((IntegraUI) UI.getCurrent()).getSessionToken());
}
}
but for all Client I need to insert this line:
client.register(new AuthHeadersRequestFilter());
So, can I configure to every place i create one client, this filter will be registered automatic?
tks
A step back
How many Client instances are you playing with?
Client instances are heavy-weight objects and you are supposed to have only a small number of instances and reuse them when possible. Have a look at the documentation:
Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a Client instance may be a rather expensive operation. It is therefore advised to construct only a small number of Client instances in the application. Client instances must be properly closed before being disposed to avoid leaking resources.
Registering filters and interceptors
RESTEasy won't register filters and interceptors automatically on your Client. It happens on server side when a filter or interceptor is annotated with #Provider. But on client side, you must register the filters and interceptors manually.
Instead of registering filters and interceptors in the Client instance, you could register them in a Configuration instance and use it to create the Client instance:
Configuration config = new Configuration();
config.register(MyClientResponseFilter.class);
config.register(new AnotherClientFilter());
Client client = ClientBuilder.newClient(config);
It might be useful when creating more than one client with the same configuration.
I looked for the similar question but could not find any . I have a micro service created with drop-wizard which is running in localhost:9000.
I am working in another project(with spring mvc) running in 8080. I wan to call the above service which gives me string back from any of my controllers in main project .lets say the path is "localhost:9000/giveMeString" .
You can use Apache's HTTP Client. See this example borrowed from their documentation:
// Create an instance of HttpClient.
HttpClient client = new HttpClient();
// Create a method instance.
GetMethod method = new GetMethod("http://localhost:9000/giveMeString");
// Execute the method.
int statusCode = client.executeMethod(method);
// Read the response body.
byte[] responseBody = method.getResponseBody();
//Print the response
System.out.println(new String(responseBody));
If you're really going down the microservice path, note that creating an HTTP client for every request and making synchronous, blocking requests won't really scale.
Here are a few ideas, if you're using Spring:
Create a single RestTemplate instance
You can create a single RestTemplate instance and inject it in multiple places in your application.
#Configuration
public class MyConfiguration {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory());
}
}
Better, wrap that REST client with a Cache
Check out Sagan's take on this.
Even better, go asynchronous
You can use an AsyncRestTemplate; very useful, especially if your Controllers need to make multiple requests and if you don't want to block your webapp thread. Your Controller can even return a DeferredResult or a ListenableFuture, which will make your webapp more scalable.
And Spring Cloud + Netflix
You can also check Spring Cloud and Spring Cloud Netflix.
You'll see there interesting features: load-balancing, recovery, circuit breakers, etc.
I'm writing a simple Google Web Toolkit service which acts as a proxy, which will basically exist to allow the client to make a POST to a different server. The client essentially uses this service to request an HTTP call. The service has only one asynchronous method call, called ajax(), which should just forward the server response. My code for implementing the call looks like this:
class ProxyServiceImpl extends RemoteServiceServlet implements ProxyService {
#Override
public Response ajax(String data) {
RequestBuilder rb = /*make a request builder*/
RequestCallback rc = new RequestCallback() {
#Override
public void onResponseReceived(Response response) {
/* Forward this response back to the client as the return value of
the ajax method... somehow... */
}
};
rb.sendRequest(data, requestCallback);
return /* The response above... except I can't */;
}
}
You can see the basic form of my problem, of course. The ajax() method is used asynchronously, but GWT decides to be smart and hide that from the dumb old developer, so they can just write normal Java code without callbacks. GWT services basically just do magic instead of accepting a callback parameter.
The trouble arises, then, because GWT is hiding the callback object from me. I'm trying to make my own asynchronous call from the service implementation, but I can't, because GWT services assume that you behave synchronously in service implementations. How can I work around this and make an asynchronous call from my service method implementation?
You are mixing up client and server side code. In ProxyServiceImpl, you CANNOT use RequestBuilder. RequestBuilder is a client side class which will only execute in the browser.
A server-to-server http call is always synchronous. Instead of using RequestBuilder, you should make use of a library like HttpClient, get the results and then send it back to the client. That would solve the problem you are facing.
But I should add, you DO NOT want to build a proxy at the application level. You could just as well use a http proxy such as apache's mod_proxy.