Spring Cloud Contract and Zuul - spring-cloud

Using Spring Cloud Dalston, we have built a proxy service that, of course, uses Zuul. I am now trying to add Spring Cloud Contract tests to verify our proxy service works as expected from a contract adherence perspective. What is strange is that I can send a request and receive a 200 status code back, but the expected response body, content type header, etc. is empty, and my tests fail as a result.
Are there additional configurations not specified in the Spring Cloud Contract documentation necessary for testing services that use Zuul capabilities?

Here you have an example https://github.com/spring-cloud/spring-cloud-contract/issues/450
/**
* Abstraction of configuration to test contracts with external microservices which are using a zuul-gateway in between.
*
* When a provider of data only allows communication through a Zuul-Gateway, a special way to ensure valid contracts is needed.
* The Goal is to emulate the Zuul-Interception to be able to use the contracts stored within the providing service.
*
* F.e.: Consumer-Service consumes the Provider-Service, but the provider can not be called directly.
* The Consumer-Service calls an URL with a prefix consisting of the name of the gateway ("gateway") and name of the
* service (in this example "Provider-Service"). For example: http://gateway/provider/path/to/resource.
* The contract provided by Provider-Service holds only a part of the provided URL (here: "/path/to/resource").
* The resolution of "gateway" and "provider" is done within this class.
*/
#RunWith(SpringRunner.class)
#SpringBootTest(classes = EmbeddedZuulProxy.class,
properties = {"server.port: 8080",
"zuul.routes.provider.path: /provider/**",
"zuul.routes.provider.service-id: provider",
"zuul.routes.provider.url: http://localhost:9090/" //the url of the provider-stub is at port 9090
},
webEnvironment = WebEnvironment.DEFINED_PORT) //defined port is important! Ribbon points to zuul, which then points to the provider-stub
#AutoConfigureMockMvc
#AutoConfigureJsonTesters
//the stub runs on fixed port 9090, so that zuul can point to it
#AutoConfigureStubRunner(ids = "<group-id>:<artifact-id>:+:stubs:9090")
#DirtiesContext
public abstract class ZuulContractBase {
}
/**
* Configuration and Setup of an embedded Zuul-Gateway.
* This way it is possible to use contracts, stored in providing service
*/
#Configuration
#ComponentScan(basePackages = "<path.to.feign.client>") //autowiring feign client
#EnableAutoConfiguration
#EnableZuulProxy
#EnableFeignClients
#RibbonClient(name = "gateway", configuration = SimpleRibbonClientConfiguration.class)
class EmbeddedZuulProxy {
#Bean
RouteLocator routeLocator(DiscoveryClient discoveryClient,
ZuulProperties zuulProperties) {
return new DiscoveryClientRouteLocator("/", discoveryClient, zuulProperties);
}
}
/**
* Ribbon Load balancer with fixed server list for "simple" pointing to localhost,
* which holds the mocked zuul-gateway
*
* f.e. a call with feign would normally look like:
* http://gateway/provider/rest/path/to/your/{url}
* which is mapped to:
* http://localhost:{zuulport}/provider/rest/path/to/your/{url}
*/
#Configuration
class SimpleRibbonClientConfiguration {
#Value("${server.port}")
private Integer zuulPort;
#Bean
public ServerList<Server> ribbonServerList() {
return new StaticServerList<>(new Server("localhost", zuulPort));
}
}

Related

RestTemplate.postForObject() java.net.SocketTimeoutException: Read timed out EVEN THOUGH SUCCESSFUL

I have two Java Spring Boot web service apps on the same server calling each other via REST. Service A calls Service B and the latter successfully acts upon the notfication.
THE PROBLEM is that Service A never receives the acknowlegement from Service B, so it thinks it has failed, and in accordance with its looping recovery logic, it tries again…and again…and again. Service B ends up doing 3 times the work for no added benefit.
The relevant code (stripped down and falsified to protect the guilty) is as follows:
Service A:
public void giveOrderToServiceB(#RequestBody CustomClass message) {
...
org.springframework.web.client.RestTemplate template = new RestTemplate(clientHttpRequestFactory());
com.mycompany.CustomReply reply = template.postForObject(serviceBUrl, message, CustomReply.class);
Service B REST Controller:
#PostMapping(value="ExecuteTheWork", produces=org.springframework.http.MediaType.APPLICATION_JSON_VALUE, consumes=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody CustomReply executeTheWork(#RequestBody CustomClass thing) {
// do something with the thing...
CustomReply reply = new CustomReply();
reply.setReply("Successfully executed the work.");
return reply;
}
The actual exception caught by Service A after calling RestTemplate.postForObject() is
java.net.SocketTimeoutException: Read timed out
Please advise.
OK, I think I got it. I don't send the response back from Service B until after the method has completed all of its work, which can take several seconds to several minutes.
If I immediately answer (and skip the processing), it works consistently.
Need to spin off the actual work to a separate thread.
Cheeers
When you are registering the bean of rest template in your application it must then configure it with a timeout. Following is the Spring application config file
package com.temp.project.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
#Configuration
public class TempProjectConfig {
/**
* Set Timeout for HTTP requests
* #return
*/
#Bean
public ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 1200000; // here is the timeout property set for rest template
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
/**
* RestTemplate to call REST endpoints
* #param clientHttpRequestFactory
* #return
*/
#Bean
public RestTemplate getRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
return new RestTemplate(clientHttpRequestFactory);
}
}

How to generate pretty print docs while using spring cloud contract

Without introducing spring cloud contract, I customized the configuration of restdocs as below,
#Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
protected WebTestClient http;
#Autowired
private ApplicationContext context;
/**
* setup.
*/
#Before
public void before() {
this.http = WebTestClient.bindToApplicationContext(context)
.configureClient()
.baseUrl("http://theserver")
.filter(WebTestClientRestDocumentation
.documentationConfiguration(this.restDocumentation)
.operationPreprocessors()
.withRequestDefaults(prettyPrint())
.withResponseDefaults(prettyPrint())
)
.build();
}
However while using spring restdocs and cloud contract together, I have to use the annotation to enable rest docs and cloud contract,
#AutoConfigureRestDocs(uriHost = "theserver", uriPort = 80)
#AutoConfigureWebTestClient
public abstract class BaseTest {
Any advice how to generate pretty print docs while generating cloud contract stubs?
What you can do is not to use the #AutoConfigureRestDocs but use the API to pass to WebTestClientRestDocumentation.documentationConfiguration(...) the .snippets().withAdditionalDefaults(new WireMockSnippet()) line. That way by default you will start producing WireMock snippets and all of your previous configuration will not be discarded.

netflix feign client - RequestMethod.POST submits empty json object to service

When i send a POST request using netflix client , the json properties are blank when it hits the service consumer.
Below is my interface
#FeignClient(name = "NLPService", configuration = FooConfiguration.class )
public interface NLPServiceConsumer extends TempInterface {
}
public interface TempInterface {
#RequestMapping("/greeting")
String greeting();
#RequestMapping(method = RequestMethod.POST,value="/nlp",
consumes="application/json",produces="application/json")
NLPResponse identifyTags(NLPInputToBeTransformed nlpInputToBeTransformed);
#RequestMapping(method = RequestMethod.GET,value="/nlpGetMethod",
produces="application/json")
NLPResponse identifyTagsTest();
}
Method identifyTagsTest works and I am able to successfully get the response .
This method is a GET method with no input
When I try a POST method , passing a object as parameter , at the end point service implementation , the object attributes are null .
Has anybody faced such issue ? Is there any mistake in my configuration ?
The problem was not at the feign client. It was at the service implementation
Spent almost a day on this issue .
The RestController also has to specify #RequestBody ( apart from the shared interface )
can #FeignClient extend - and #RestController implement - a common, fully-annotated Interface?

spring cloud + ribbon + feign + zuul + eureka

How to loadbalance micro services via Ribbon (Not feign). I have 3 micro services "M1", "M2" and "M2_duplication", "M1" is communicating with "M2" via feign. I want if "M2" get too much traffic, the requests will be forwarded to the "M2_duplication". How is this possible via #ribbonclient ?
POM M1:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
The feign call in M1:
//name is taken from Eureka(service registry)
#FeignClient(name = "M1")
public interface M1ServiceClient {
#RequestMapping(method = RequestMethod.GET, value = "/getAllM2")
Map<String, String> getAllM2();
}
Application M1:
#EnableConfigurationProperties()
#SpringBootApplication
#EnableEurekaClient
#EnableFeignClients
public class PortefeuilleApplication {
public static void main(String[] args) {
SpringApplication.run(PortefeuilleApplication.class, args);
}
}
Your question is rather vague ... for example, you specifically state 'not feign' and then show a FeignClient. Nevertheless it looks like you are asking how to implement an availability pattern for your ribbon load balancer. To do this, you create a Ribbon Configuration class and then override the load balancer strategy rule. For example:
#Configuration
public class MyConfiguration {
#Bean
public IRule ribbonRule() {
return new RoundRobinRule();
}
}
There are a number of existing Ribbon Rule strategies around availability e.g. AvailabilityFilteringRule or BestAvailableFilter, but if none of these suit you could also write your own Rule. Once you have your class, amend your RibbonClient annotation to reference it, e.g:
#RibbonClient(name = "myClient", configuration = MyConfiguration.class)
You can find more information here: https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers

Proxy in Docusign Credential API

Following the Examples of Docusign SDK located at
https://github.com/docusign/DocuSign-SOAP-SDK
Trying to implement the Credential API, code is something listed below
public LoginResult getCredentialAPI() {
CredentialSoap credApi = new CredentialFactory().getCredential(credentialURL);
LoginResult result = credApi.login("[" + integratorKey + "]" + username, password, true);
return result;
}
I am getting a Connection Times out Error, The reason been I have to use Proxy connection setting to make the connection, where do I add the server URL and port for proxy connections. The class Credential Factory is listed below
public class CredentialFactory {
/**
* Builds the API interface in order to use the Docusign Credential API.
*
* #param webserviceEndpoint the endpoint for the credential webservice
* #return the credential api stub
*/
public CredentialSoap getCredential(String webserviceEndpoint) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
setupService(factory, webserviceEndpoint);
CredentialSoap credentialProxy = (CredentialSoap) factory.create();
return credentialProxy;
}
/**
* Set service class and webservice url.
*
* #param factory
* #param webserviceEndpoint the endpoint for the credential webservice
*/
protected void setupService(JaxWsProxyFactoryBean factory, String webserviceEndpoint) {
factory.setServiceClass(CredentialSoap.class);
factory.setAddress(webserviceEndpoint);
}
}
Proxy settings are stack-dependent. So the setting is usually below the level of the SOAP call. What stack are you using?
Judging from your variable name, you're using JAX-WS. In that case, see
https://stackoverflow.com/a/6447240/64904