In this tutorial, we keep the contracts together with the producer code. On the consumer side, we be using Service Discovery.
Scenarios


Flow

Tutorial
Using Consumer Driven Contracts is like using TDD at the architecture level. We start by writing a test on the consumer side.
Consumer flow 1

Let’s go back to our consumer code. We need to look at BeerControllerTest
and
BeerController
. We know how we would like the API to look, so now we can write the
missing implementation in the BeerController
.
Tip
|
Remember that, in order to use the load balancing features, we need to add the
org.springframework.cloud:spring-cloud-starter-netflix-eureka-client dependency.
|
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
Also, you need to register the RestTemplate
bean as @LoadBalanced
. Go to
the ClientApplication
class and register the bean as follows:
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
Now let’s assume that we call the producer application by using the
http://somenameforproducer/check
URL. You need to provide some properties to tell Stub
Runner that the given service name (in our case, somenameforproducer
) should be mapped
to the running HTTP server stub of a given producer. Let’s set those properties.
Stub Runner requires you to set the stubrunner.idsToServiceIds
mapping in which the key
is the artifact ID and the value is the service name in the code. You also need to define
the idsToServiceIds
property, as shown in the following code:
stubrunner:
idsToServiceIds:
beer-api-producer: somenameforproducer
When you call the URL http://somenameforproducer/check
, it will get redirected to a
fake HTTP instance that was started with the beer-api-producer
stubs JAR. We know how
the API needs to look, so we can now go ahead and try to write the missing implementation
of the BeerController
.
Writing the Missing Consumer HTTP Implementation
-
Let’s go back to our, consumer’s code - let’s go back to the
BeerControllerTest
andBeerController
. We know how we would like the API to look like so now we can write the missing implementation in theBeerController
. Let’s assume that the producer application will be running athttp://localhost:8090/
. Now go ahead and try to write the missing implementation of theBeerController
-
In case of any issues you can check out the solution
Turning on Stub Runner in HTTP Consumer Tests
-
Now it’s time to turn on the magic! Let’s add the Spring Cloud Starter Contract Stub Runner test dependency.
Maven<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-contract-stub-runner</artifactId> <scope>test</scope> </dependency>
GradletestImplementation("org.springframework.cloud:spring-cloud-starter-contract-stub-runner")
-
We can annotate our test class with
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL, ids = "com.example:beer-api-producer:+:stubs:8090")
. What that will do is:-
it will download the stub JARs from Maven local (
stubsMode = StubRunnerProperties.StubsMode.LOCAL
) -
it will search for a JAR with coordinates
com.example:beer-api-producer
with latest version (+
) andstubs
classifier. Once it’s found the fake HTTP server stub will be started at port8090
-
-
Rerun the test - it should automagically pass!
-
In the logs you will see information about downloading, unpacking and starting stubs (see the logs)
-
What happened is that we could interact with real API without writing a single line of production code
-
Playing with the HTTP Contracts
-
TDD is about red, green and refactor. We went through the first two. Time to refactor the code. We come to the conclusion that the
name
field is unnecessary. In theBeerController.java
file let’s create a new class calledBeerRequest
that will contain only age field and let’s try to send that to our stubbed producer. (Show solution) -
Let’s run the tests again - what will happen is that the tests will fail. That’s because in the contract you have explicitly described that you want the
name
to be there. As you can see all the typos will be caught during the build time of your project.-
The same will happen if you leave the
name
but change theage
to some other value (e.g. 28). Our stubs at the moment are very strict. We’ll try to fix that in a second
-
-
To fix this you need to go back with your IDE to the producer and modify your HTTP contracts.
-
Just remove the
name
field from the request body. -
Spring Cloud Contract allows you to provide dynamic values for parts of body, urls, headers etc. This is especially useful when working with dates, database ids, UUIDs etc.
-
Let’s open the
shouldGrantABeerIfOldEnough.groovy
and go to the request bodyage
element -
Instead of
22
write$(regex('[2-9][0-9]'))
. Now let’s analyze what this is.-
In order to tell Spring Cloud Contract that there will be a dynamic value set you have to use either the
$()
orvalue()
method. They are equivalent. -
Next we use
regex()
method that converts yourString
intoPattern
. In this case we assume a 2 digit number greater or equal to20
-
-
Repeat the same process for the
shouldRejectABeerIfTooYoung.groovy
contract but change the regular expression to[0-1][0-9]
-
Run the building with test skipping and check the output of stubs. You’ll see that the generated mappings have changed from equality check in JSON Path to regular expression check
-
Go back to the consumer code and run the
BeerControlerTest
again. This time it should pass. You can also change the values of age to e.g.45
for the positive case and11
for the negative on.
-
Congratulations! As a consumer, you have successfully used the API of the producer for both HTTP and messaging. Now you can file a pull request (PR) to the producer code with the proposal of the contract,
Let’s switch to the producer side.
Producer Flow 1

IDE setup
-
Open in your IDE the
producer
project (either via Maven or Gradle) -
We’re assuming that we’ve taken over the PR. Example of how to achieve that in "real life" for a PR that got submitted to via a branch called
the_pr
looks like this:
git fetch origin
git checkout -b the_pr origin/the_pr
git merge master
-
The idea of Spring Cloud Contract is about stub and contract validity. Right now we have a set of contracts defined but we haven’t tested it against the producer side. Time to change that!
Setting up the Spring Cloud Contract plugin
-
Spring Cloud Contract can generate tests from your contracts to ensure that your implementation’s API is compatible with the defined contract. Let’s set up the project to start generating tests.
-
Spring Cloud Contract needs a base class that all of the generated tests will extend. Currently we support 3 different ways of defining a base class (you can read more about this in the Spring Cloud Contract documentation for Gradle and Maven)
-
a single class for all tests
-
convention based naming (takes 2 last package names and appends
Base
. Having a contractsrc/test/resources/contracts/foo/bar/shouldDoSth.groovy
would create a test class calledBarTest
that would extendFooBarBase
class. -
manual mapping (you can state that contracts matching certain regular expression will have to have a base class with fully qualified name equal to X)
-
-
In the following example we’ll play with convention based naming
-
For Maven under the plugin setup you have to set up the plugin configuration
<configuration><packageWithBaseClasses>com.example</packageWithBaseClasses></configuration>
Maven<plugin> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-contract-maven-plugin</artifactId> <version>${spring-cloud-contract.version}</version> <extensions>true</extensions> <configuration> <packageWithBaseClasses>com.example</packageWithBaseClasses> </configuration> </plugin>
Gradlecontracts { testFramework = "JUNIT5" packageWithBaseClasses = 'com.example' }
-
In both cases passing of that value tells the plugin that a given base class is available under the
com.example
package
-
-
Updating Contracts from the PR
Generating tests from contracts
-
Let’s generate the tests! Just call:
Maven$ ./mvnw clean install
Gradle$ ./gradlew clean build publishToMavenLocal
-
Suddenly some tests should start failing. Those tests are the autogenerated tests created by Spring Cloud Contract
-
The tests lay under
/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/beer
intarget
for Maven orbuild
for Gradle -
There will be a test for each folder in which you store your contracts. The name of the test class will be the name of that folder
-
Each of the contracts will be a single test inside that test class
-
If you check out the generated tests you’ll notice that the dynamic parts of the
request
part of the contract got converted to a concrete value. Any dynamic bits on theresponse
side would be converted into matchers.
-
-
Time to fix the broken tests. We need to do that by providing the missing implementation.
Fixing broken HTTP tests
-
Let’s start with HTTP
-
First let’s write the missing implementation in
ProducerController
. The logic to be written is extremely simple - if thepersonCheckingService.shouldGetBeer(…)
returnstrue
then we should returnnew Response(BeerCheckStatus.OK)
. Otherwisenew Response(BeerCheckStatus.NOT_OK)
. (Show solution)
-
-
Let’s fix the
BeerRestBase
class now-
The idea of CDC is NOT TO TEST every single feature. Contract tests are there to see if the API is matched, NOT that the feature is working. That’s why we shouldn’t be accessing databases etc. That means that we will work with mock of the
PersonCheckingService
. (Show solution) -
Let’s annotate the test class with
@RunWith(MockitoJUnitRunner.class)
to enable Mockito runner.@RunWith(MockitoJUnitRunner.class) public abstract class BeerRestBase { ... }
-
We’ll want to test the
ProducerController
so we can create a field@InjectMocks ProducerController producerController
. Mockito will inject any mocks for us via the constructor.@Mock PersonCheckingService personCheckingService; @InjectMocks ProducerController producerController; @BeforeEach public void setup() { given(personCheckingService.shouldGetBeer(argThat(oldEnough()))).willReturn(true); }
-
It won’t compile cause we don’t have the
oldEnough()
method but don’t worry. So this line stubs theshouldGetBeer
method in such a way that if the user is old enough then the method will return true. Let’s now add theoldEnoughMethod()
private TypeSafeMatcher<PersonToCheck> oldEnough() { return new TypeSafeMatcher<PersonToCheck>() { @Override protected boolean matchesSafely(PersonToCheck personToCheck) { return personToCheck.age >= 20; } @Override public void describeTo(Description description) { } }; }
-
We’re using the
TypeSafeMatcher
from Hamcrest to create a matcher forPersonToCheck
. In this case if the person to check is older or is 20 then the methodshouldGetBeer
method will returntrue
. -
Now we need to configure RestAssured that is used by Spring Cloud Contract to send requests. In our case we want to profit from MockMvc. In order to set the
ProducerController
with RestAssured it’s enough to call// https://github.com/spring-cloud/spring-cloud-contract/issues/1428 EncoderConfig encoderConfig = new EncoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false); RestAssuredMockMvc.config = new RestAssuredMockMvcConfig().encoderConfig(encoderConfig); RestAssuredMockMvc.standaloneSetup(producerController);
@RunWith(MockitoJUnitRunner.class) public abstract class BeerRestBase { @Mock PersonCheckingService personCheckingService; @InjectMocks ProducerController producerController; @BeforeEach public void setup() { given(personCheckingService.shouldGetBeer(argThat(oldEnough()))).willReturn(true); // https://github.com/spring-cloud/spring-cloud-contract/issues/1428 EncoderConfig encoderConfig = new EncoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false); RestAssuredMockMvc.config = new RestAssuredMockMvcConfig().encoderConfig(encoderConfig); RestAssuredMockMvc.standaloneSetup(producerController); } private TypeSafeMatcher<PersonToCheck> oldEnough() { return new TypeSafeMatcher<PersonToCheck>() { @Override protected boolean matchesSafely(PersonToCheck personToCheck) { return personToCheck.age >= 20; } @Override public void describeTo(Description description) { } }; } }
-
With mocks and RestAssured setup - we’re ready to run our HTTP based autogenerated tests
-
Now you could merge the PR to master, and your CI system would build a fat jar and the stubs.
Congratulations! You’ve completed the producer side of this tutorial.
Consumer flow 2

-
After merging the PR the producer’s stubs reside in some Artifactory / Nexus instance
-
As consumers we no longer want to retrieve the stubs from our local Maven repository - we’d like to download them from the remote location
-
To do that (we won’t do that for the tutorial but you would do it in your "production" code) it’s enough to pass the
repositoryRoot
parameter and set thestubsMode
toStubRunnerProperties.StubsMode.REMOTE
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.MOCK) @AutoConfigureMockMvc @AutoConfigureJsonTesters @AutoConfigureStubRunner( repositoryRoot="http://www.foo.com/bar, ids = "com.example:beer-api-producer:+:stubs:8090", stubsMode = StubRunnerProperties.StubsMode.REMOTE ) @DirtiesContext public class YourTestOnTheConsumerSide extends AbstractTest { }
-
Another option is to pass the property
stubrunner.repositoryRoot
either as a system / environment property, or via anapplication.yml
andstubrunner.stubs-mode
equal toremote
-
Solutions
Written consumer tests
@Test
public void should_give_me_a_beer_when_im_old_enough() throws Exception {
//remove::start[]
this.mockMvc.perform(MockMvcRequestBuilders.post("/beer")
.contentType(MediaType.APPLICATION_JSON)
.content(this.json.write(new Person("marcin", 22)).getJson()))
.andExpect(status().isOk())
.andExpect(content().string("THERE YOU GO"));
//remove::end[]
}
@Test
public void should_reject_a_beer_when_im_too_young() throws Exception {
//remove::start[]
this.mockMvc.perform(MockMvcRequestBuilders.post("/beer")
.contentType(MediaType.APPLICATION_JSON)
.content(this.json.write(new Person("marcin", 17)).getJson()))
.andExpect(status().isOk())
.andExpect(content().string("GET LOST"));
//remove::end[]
}
Adding Spring Cloud Contract Dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>
testImplementation("org.springframework.cloud:spring-cloud-starter-contract-verifier")
Proposal of simple contracts by consumer
HTTP communication
// rest/shouldGrantABeerIfOldEnough.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Represents a successful scenario of getting a beer
```
given:
client is old enough
when:
he applies for a beer
then:
we'll grant him the beer
```
""")
request {
method 'POST'
url '/check'
body(
age: 22,
name: "marcin"
)
headers {
contentType(applicationJson())
}
}
response {
status 200
body("""
{
"status": "OK"
}
""")
headers {
contentType(applicationJson())
}
}
}
// rest/shouldRejectABeerIfTooYoung.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Represents a successful scenario of getting a beer
```
given:
client is old enough
when:
he applies for a beer
then:
we'll grant him the beer
```
""")
request {
method 'POST'
url '/check'
body(
age: 17,
name: "marcin"
)
headers {
contentType(applicationJson())
}
}
response {
status 200
body("""
{
"status": "NOT_OK"
}
""")
headers {
contentType(applicationJson())
}
}
}
Messaging communication
// messaging/shouldSendAcceptedVerification.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Sends a positive verification message when person is eligible to get the beer
```
given:
client is old enough
when:
he applies for a beer
then:
we'll send a message with a positive verification
```
""")
// Label by means of which the output message can be triggered
label 'accepted_verification'
// output message of the contract
outputMessage {
// destination to which the output message will be sent
sentTo 'verifications'
// the body of the output message
body(
eligible: true
)
headers {
header("contentType", applicationJsonUtf8())
}
}
}
// messaging/shouldSendRejectedVerification.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Sends a negative verification message when person is not eligible to get the beer
```
given:
client is too young
when:
he applies for a beer
then:
we'll send a message with a negative verification
```
""")
// Label by means of which the output message can be triggered
label 'rejected_verification'
// output message of the contract
outputMessage {
// destination to which the output message will be sent
sentTo 'verifications'
// the body of the output message
body(
eligible: false
)
headers {
header("contentType", applicationJsonUtf8())
}
}
}
Missing consumer controller code
ResponseEntity<Response> response = this.restTemplate.exchange(
RequestEntity
.post(URI.create("http://localhost:" + this.port + "/check"))
.contentType(MediaType.APPLICATION_JSON)
.body(person),
Response.class);
switch (response.getBody().status) {
case OK:
return "THERE YOU GO";
default:
return "GET LOST";
}
Stub Logs
2017-05-11 12:16:51.146 INFO 4693 --- [ main] o.s.c.c.s.StubDownloaderBuilderProvider : Will download stubs using Aether
2017-05-11 12:16:51.148 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Remote repos not passed but the switch to work offline was set. Stubs will be used from your local Maven repository.
2017-05-11 12:16:51.291 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Desired version is [+] - will try to resolve the latest version
2017-05-11 12:16:51.308 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved version is [0.0.1-SNAPSHOT]
2017-05-11 12:16:51.309 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolving artifact [com.example:{producer_artifact}:jar:stubs:0.0.1-SNAPSHOT] using remote repositories []
2017-05-11 12:16:51.317 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Resolved artifact [com.example:{producer_artifact}:jar:stubs:0.0.1-SNAPSHOT] to /home/marcin/.m2/repository/com/example/{producer_artifact}/0.0.1-SNAPSHOT/{producer_artifact}-0.0.1-SNAPSHOT-stubs.jar
2017-05-11 12:16:51.322 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacking stub from JAR [URI: file:/home/marcin/.m2/repository/com/example/{producer_artifact}/0.0.1-SNAPSHOT/{producer_artifact}-0.0.1-SNAPSHOT-stubs.jar]
2017-05-11 12:16:51.327 INFO 4693 --- [ main] o.s.c.c.stubrunner.AetherStubDownloader : Unpacked file to [/tmp/contracts9053257535983128167]
2017-05-11 12:16:52.608 INFO 4693 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@699e0bf0: startup date [Thu May 11 12:16:52 CEST 2017]; root of context hierarchy
2017-05-11 12:16:52.684 INFO 4693 --- [ main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2017-05-11 12:16:52.837 INFO 4693 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8090 (http)
2017-05-11 12:16:52.851 INFO 4693 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-05-11 12:16:52.853 INFO 4693 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.14
2017-05-11 12:16:52.975 INFO 4693 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-05-11 12:16:52.975 INFO 4693 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 367 ms
2017-05-11 12:16:52.996 INFO 4693 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'stub' to [/]
2017-05-11 12:16:53.000 INFO 4693 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'admin' to [/__admin/*]
2017-05-11 12:16:53.135 INFO 4693 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8090 (http)
2017-05-11 12:16:53.139 INFO 4693 --- [ main] o.s.c.contract.stubrunner.StubServer : Started stub server for project [com.example:{producer_artifact}:0.0.1-SNAPSHOT:stubs] on port 8090
Beer Request
class BeerRequest {
public int age;
public BeerRequest(int age) {
this.age = age;
}
public BeerRequest() {
}
}
Missing listener code
if (verification.eligible) {
this.eligibleCounter.incrementAndGet();
} else {
this.notEligibleCounter.incrementAndGet();
}
Missing triggers
@Test public void should_increase_the_eligible_counter_when_verification_was_accepted() throws Exception {
int initialCounter = this.listener.eligibleCounter.get();
//remove::start[]
this.stubTrigger.trigger("accepted_verification");
//remove::end[]
then(this.listener.eligibleCounter.get()).isGreaterThan(initialCounter);
}
@Test public void should_increase_the_noteligible_counter_when_verification_was_rejected() throws Exception {
int initialCounter = this.listener.notEligibleCounter.get();
//remove::start[]
this.stubTrigger.trigger("rejected_verification");
//remove::end[]
then(this.listener.notEligibleCounter.get()).isGreaterThan(initialCounter);
}
Messaging DSLs
// messaging/shouldSendAcceptedVerification.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Sends a positive verification message when person is eligible to get the beer
```
given:
client is old enough
when:
he applies for a beer
then:
we'll send a message with a positive verification
```
""")
// Label by means of which the output message can be triggered
label 'accepted_verification'
// input to the contract
input {
// the contract will be triggered by a method
triggeredBy('clientIsOldEnough()')
}
// output message of the contract
outputMessage {
// destination to which the output message will be sent
sentTo 'verifications'
// the body of the output message
body(
eligible: true
)
headers {
header("contentType", applicationJsonUtf8())
}
}
}
// messaging/shouldSendRejectedVerification.groovy
org.springframework.cloud.contract.spec.Contract.make {
description("""
Sends a negative verification message when person is not eligible to get the beer
```
given:
client is too young
when:
he applies for a beer
then:
we'll send a message with a negative verification
```
""")
// Label by means of which the output message can be triggered
label 'rejected_verification'
// input to the contract
input {
// the contract will be triggered by a method
triggeredBy('clientIsTooYoung()')
}
// output message of the contract
outputMessage {
// destination to which the output message will be sent
sentTo 'verifications'
// the body of the output message
body(
eligible: false
)
headers {
header("contentType", applicationJsonUtf8())
}
}
}
ProducerController implementation
if (personCheckingService.shouldGetBeer(personToCheck)) {
return new Response(BeerCheckStatus.OK);
}
return new Response(BeerCheckStatus.NOT_OK);
BeerRestBase
@RunWith(MockitoJUnitRunner.class)
public abstract class BeerRestBase {
@Mock PersonCheckingService personCheckingService;
@InjectMocks ProducerController producerController;
@BeforeEach
public void setup() {
given(personCheckingService.shouldGetBeer(argThat(oldEnough()))).willReturn(true);
// https://github.com/spring-cloud/spring-cloud-contract/issues/1428
EncoderConfig encoderConfig = new EncoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false);
RestAssuredMockMvc.config = new RestAssuredMockMvcConfig().encoderConfig(encoderConfig);
RestAssuredMockMvc.standaloneSetup(producerController);
}
private TypeSafeMatcher<PersonToCheck> oldEnough() {
return new TypeSafeMatcher<PersonToCheck>() {
@Override protected boolean matchesSafely(PersonToCheck personToCheck) {
return personToCheck.age >= 20;
}
@Override public void describeTo(Description description) {
}
};
}
}
BeerMessagingBase
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ProducerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@AutoConfigureMessageVerifier
@ImportAutoConfiguration(TestChannelBinderConfiguration.class)
public abstract class BeerMessagingBase {
@Inject MessageVerifier messaging;
@Autowired PersonCheckingService personCheckingService;
@BeforeEach
public void setup() {
// let's clear any remaining messages
// output == destination or channel name
this.messaging.receive("output", 100, TimeUnit.MILLISECONDS);
}
public void clientIsOldEnough() {
personCheckingService.shouldGetBeer(new PersonToCheck(25));
}
public void clientIsTooYoung() {
personCheckingService.shouldGetBeer(new PersonToCheck(5));
}
}
Messaging implementation
boolean shouldGetBeer = personToCheck.age >= 20;
this.source.send("output-out-0", new Verification(shouldGetBeer));
return shouldGetBeer;
Missing Consumer Controller Code with Discovery
ResponseEntity<Response> response = this.restTemplate.exchange(
RequestEntity
.post(URI.create("http://somenameforproducer/check"))
.contentType(MediaType.APPLICATION_JSON)
.body(person),
Response.class);
switch (response.getBody().status) {
case OK:
return "THERE YOU GO";
default:
return "GET LOST";
}