Spring Reactive Programming Repeat - reactive-programming

I have a simple scenario which i am unable to code using reactive programming
I have a serviceA which return someresponse which is then passed to a validator method,
this validator method can return 3 possible values as Enum each for
validationSuccessful
validationError
RetryServiceA
If returned enum is retryServiceA , then i need to recallServiceA, else if there is validation error I need to call serviceB and merge response of service A(passed and param) and serviceB and return the response

Related

Client side error handling with Micronaut

I am using a Micronaut layer between a REST service and a consumer app.
|REST service|->|Micronaut client / controller|->|consumer app|.
When the REST service is returning an error, the controller should propagate the error code.
When the REST service is offline, the controller should return some kind of 500 error code.
However, right now it's returning an empty body with a 200 error code in both cases.
For the example here is my controller:
#Controller("/api/v1")
public class MyController {
private final ClientNetworkList clientNetworkList;
public MyController(
ClientNetworkList clientNetworkList,
){
this.clientNetworkList = clientNetworkList;
}
#Get(uri = "/networkList", produces = MediaType.APPLICATION_JSON_STREAM)
Flowable<NetworkListPackage> packagesNetworkList() {
return clientNetworkList.fetchPackages();
}
}
And the client:
#Client(FabricConfiguration.FABRIC_API_URL)
public interface ClientNetworkList{
#Get("/auth/networklist")
Flowable<NetworkListPackage> fetchPackages();
}
How can I propagate or throw the correct body and error code?
How should I use the #Error annotation, should it be implemented in the controller or in a filter?
Micronaut has a Circuit Breaker Support for such things.
I would recommend to use the #Fallback Annotation and throw an Exception which will produce the 500 Error Code. See 7.3.7 Client Fallback in Micronaut Documentation.

Call not propagating to the service method from Spring Reactive Controller

I am a beginner to the spring webflux. We are currently migrating our application to Spring Webflux. No I have stuck with a problem. The following is my scenario.
The main service class is calling the following service classes for data
StudentService - return Mono<Student>
StaffService - return Mono<Staff>
Here I have a wrapper class StudentWithMentor to store the result from these service classes.
public class StudentWithMentor {
private Student student;
private Staff mentor;
}
Now in controller I am calling the above 2 services and map it into 'StudentWithMentor' in the following way
Mono<StudentWithMentor> studentWithMentorMono = Mono.just(new StudentWithMentor());
return studentWithMentorMono.map(s->{
studentService.getStudentById(id)
.doOnSuccess(s::setStudent)
.doOnSuccess(st->staffService.getStaffByGrade(st.getGrade()));
return s;
});
But when I call this endpoint I am getting the following result in postman
{
"student": null,
"mentor": null
}
Note: I am getting result from the underlying services when I debugg. But the call is returning before it process.
How can I achieve this in a complete non-blocking way.
Appreciates any help.
The easiest way will be to to use a zipWith operator to merge the results into StudentWithMentor object.
See the code below:
Mono<StudentWithMentor> studentWithMentorMono = studentService.getStudentById(id)
.zipWhen(student -> staffService.getStaffByGrade(student.getGrade()), StudentWithMentor::new);

How can I use then() block with RestAssured while using POJO classes?

While working on RestAssured I came across the concept of Serialization and DeSerialization(POJO Classes) to read and validate the response. I went through some tutorial and was able to create the POJO class based on my response.
However, when I use the POJO class reference in my Tests I am not able to use the then() block for different assertions. Below details might clear things bit more :
TestMethod without POJO :
public void listUsers() {
RestAssured.baseURI="https://reqres.in/";
Response res = RestAssured.given()
.contentType("application/json")
.queryParam("page", 2)
.when()
.get("/api/users")
.then()
.assertThat().statusCode(200).and()
.body("page", Matchers.equalTo(2)).and()
.body("total", Matchers.greaterThanOrEqualTo(1))
.body("data.email", Matchers.hasItem("george.edwards#reqres.in"))
.extract().response();
JsonPath jsonpath = new JsonPath(res.asString());
System.out.println(jsonpath.get("data[0].email"));
}
Test Method with POJO :
public void listUserswithPOJO() {
RestAssured.baseURI="https://reqres.in/";
ListUsers res = RestAssured.given()
.contentType("application/json")
.queryParam("page", 2)
.when()
.get("/api/users").as(ListUsers.class);
System.out.println(res.getData().get(1).getEmail());
}
Test Class :
#Test
public void listUsersTest() {
ReqResApi TS1 = new ReqResApi();
TS1.listUserswithPOJO();
}
I want to keep the assertions of the then block as it is while using POJO classes as well. When I try to do so after as(ListUser.class), it gives the compilation error that then() is undefined for ListUser class.
Is there any way in which I can use both POJO class as well as then() block in my rest assured tests.
This is not possible because Return types of these options are different.
MainPojo m1 =RestAssured.given().contentType("application/json").queryParam("page", 2).when().get("/api/users")
.as(MainPojo.class)==> Return Type is ur Class, in this example Main Pojo
System.out.println(m1.getData().get(0).getFirst_name());
RestAssured.given().contentType("application/json").queryParam("page", 2).when()
.get("/api/users").then().assertThat().statusCode(200).and().body("page", Matchers.equalTo(2)).and()
.body("total", Matchers.greaterThanOrEqualTo(1))
.body("data.email", Matchers.hasItem("george.edwards#reqres.in")).extract().response();---> Return Type is Response

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?

Entity of Response is null

currently I am coding on a mock for a rest service we're using. For one case I want to return a 404 with a specific message in the body:
#POST
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
#Path("/bookings")
public javax.ws.rs.core.Response performBooking(final BookingRequest booking) {
if (shouldfail(booking)) {
return Response.status(Response.Status.NOT_FOUND).entity("specific message in entity").build();
}
// some more other cases below...
}
If I test the mock with a unit test everything works fine:
final String failedMessage = response.getEntity().toString();
But if I deploy the rest service and call it, I will get the correct 404 code, but the entity is null.
For valid answers I put a BookingResponse object in the entity (simple DTO with some IDs in it) and it works for that. Just the string seems to disappear.
Any idea why my string disappears?