How to test contracts that somehow cannot be tested by feign client? - spring

We have the following contract in provider:
Contract.make {
request {
method GET()
url('/something/a/b/c') {
}
}
response {
status 400
}
}
This is a contract for an endpoint which has a required query parameter. If the query parameter is missing, then the application returns 400 (BAD_REQUEST).
Now, in the consumer, we use feign client for service interactions. When trying to test this contract, we can't find a way to test this specific contract because feign is a little bit restrictive.
The feign client endpoint:
#GetMapping("/b/c")
public List<Function> getFunctionsBy(#RequestParam #NotNull LegalFormType legalFormType) {
return facade.getBy(legalFormType);
}
How the right way would be? I was thinking at 2 things:
Create contracts that can be tested (this seems like a bad idea because we won't have contracts for every case)
Do not use the application's client (feign client) and use another tool to make the requests (I think this will introduce one more thing to take into account, the tool used).

Related

NServiceBus - Aggregate Root - Saga - Synchronous Command

Having an aggregate root User modeled as NServiceBus Saga
User.cs
public class User {
....
public string Rename(string name) {
.// some validation logic
}
...
}
UserSagaData.cs
public class UserSagaData : ContainSagaData
{
public User User { get; set;}
}
UserSaga.cs
public partial class UserSaga : Saga<RenameUser>
{
...
public async Task Handle(RenameUserimportAttendees, IMessageHandlerContext context)
{
Data.User.rename(...
}
...
}
Now i have a requirement to accept RenameUser command via REST API and give the feedback in HTTP Response, hence sending RegisterUser to message broker from Controller.Action is not an option. I need to perform command synchronously, get feedback and send http response.
First thing that came to mind is to use ISagaPersister, that is, retrieve saga by id, then invoke a command and then persist saga back to the datastore with ISagaPersister (which takes care of optimistic locking). Any thoughts on that ?
Is there alternative solutions to this problem ?
What type of feedback would you expect the RenameUser command to result in?
Can’t you just return a HTTP OK and queue up the rename command? (assuming that you have validation of the new name in place the chances of something going wrong should be slim and could be dealt with offline should the command end up in the error queue?)
An option if you really have to wait for the response is to use our callbacks package, https://docs.particular.net/nservicebus/messaging/callbacks, to enable your REST API block until the response has arrived, this way you can still using messaging behind the scenes.
What do you think?

Feign get request with body

For some reason I need to call a GET method API and pass json request body for it. I really couldn't find an example for it. I wonder if it is even supported using feign.
How can I do that using feign?
Yes, Feign supports it. You can do the same as with POST requests:
#FeignClient(name = "clientName", url = "http://localhost:8888")
public interface SampleFeignClient {
#GetMapping("/remote")
String test(#RequestBody SampleRequestBody sampleRequestBody);
}
But be aware: a lot of servers ignore body or even refuse that kind of "non-standard" requests completely (GET or HEAD with request bodies).
According to the documentation the correct way to do it would be to use the #SpringQueryMap annotation.
#FeignClient(name = "clientName", url = "http://localhost:8888")
public interface SampleFeignClient {
#GetMapping("/remote")
String test(#SpringQueryMap SampleRequestBody sampleRequestBody);
}
You can find more information here

How Api gateway combine responses form microservices

According to article https://dzone.com/articles/building-microservices-using there is a statement:
The API Gateway is responsible for request routing, composition, and protocol translation. All requests from clients first go through the API Gateway. It then routes requests to the appropriate microservice. The API Gateway will often handle a request by invoking multiple microservices and aggregating the results.
I'm wondering, based on Zuul example, how the API Gateway achiving this?
Let's imagine we have a 2 microservices, one which retrives all available product names and second one which returns descriptions of products. In monolithic architecture we would have only one request to get all needed data. In microservice architecture API gateway should combine responses (from both microservices) and return one response.
How this funcionality should be implemented? Are there any guidelines or articles on that?
Not all API gateway supports aggregation. This is an example of aggregating response of two service for a single client call using nginx.
The side effect of this being it introduces coupling at the API gateway layer.
Another possible solution is to use aggregation microservice. The main responsibility of this service is to provide a client side api. It can make multiple calls to other microservices to formulate the response for the client.See sample below
#RequestMapping(path = "/product", method = RequestMethod.GET)
public Product getProduct() {
var product = new Product();
String productTitle = informationClient.getProductTitle();
Integer productInventory = inventoryClient.getProductInventories();
if (productTitle != null) {
product.setTitle(productTitle);
} else {
product.setTitle("Error: Fetching Product Title Failed"); //Fallback to error message
}
if (productInventory != null) {
product.setProductInventories(productInventory);
} else {
product.setProductInventories(-1); //Fallback to default error inventory
}
return product;
}
Full example here

Web API - Handling the long running call when aggregating the calls

I have a web api project which works as a GateWay for other Mobile clients. When the mobile client makes a call to this Gateway it internally calls the existing services which are hosted by another project and it aggregates the results and return to the client. I have recently come across a situation when my gateway is internally making 3 calls first 2 are returning the data fast but the 3rd call is taking lot of time I want to know the best way to handle this scenario.
Ensure that the return type of API action methods is async Task<YourModelDataType>.
For example, let's say you have a HomeController controller as follows:
public class HomeController : ApiController
{
public async Task<YourModelDataType> Index()
{
return new YourModelDataType()
{
Property1 = await ApiService1.GetData(),
Property2 = await ApiService2.GetData(),
Property3 = await ApiService3.GetData(),
};
}
}
Ensure that calls to the other API projects are awaited. This improves scalability on the server side. i.e. server resources are free to serve other requests while awaiting response from other API services.

How can I use SwaggerValidator(com.atlassian.oai.validator) to validate Lagom API Response?

Well, I am stuck in this scenario that I want to use Swagger API to validate response of my Lagom Service API.
Here is some sample code:
#Test
public void shouldPayloadFromFileConformToSchema() throws Exception {
// first test the plain json is valid with schema
SwaggerRequestResponseValidator validator = SwaggerRequestResponseValidator
.createFor("my-service-schema.yaml").build();
final Request validRequest = SimpleRequest.Builder.get("/myService/AL20170730/11111555556161/191919")
.withHeader("api-key", "TESTKEY")
.build();
Response validResponse = SimpleResponse.Builder.ok()
.withBody(ValidatorTestUtil.loadResponse("my_service_sample_response_2017_03_16")).build();
ValidationReport reportForText = validator.validate(validRequest, validResponse);
logger.info(
"shouldPayloadFromFileConformToSchema() ################# VALIDATION PAYLOAD REPORT ##################");
reportForText.getMessages().forEach((m) -> {
logger.info("{}", m);
});
assertFalse(reportForText.hasErrors());
logger.info(
"shouldPayloadFromFileConformToSchema() ################# VALIDATION PAYLOAD REPORT END ##################");
logger.info(validRequest.getHeaders().toString());
SwaggerModule swagger = new SwaggerModule();
}
When This code runs It seems that it goes into the service(as it prints some logs of the service.) but not invokes the method which will the database with the given values.
I need to do something here that it invokes the method of the service and validates the response on the basis of this swagger spec.
I saw this link but didn't get the solution How to validate API in tests with Swagger?
If you're looking to validate an actual interaction against your running service I'd recommend using the RestAssured module (https://bitbucket.org/atlassian/swagger-request-validator/src/master/swagger-request-validator-restassured/)
This will let you execute a request against your running service and then validate that the request/response interaction matches your swagger specification.
There's an example of its use in the examples module - https://bitbucket.org/atlassian/swagger-request-validator/src/master/swagger-request-validator-examples/src/test/java/com/atlassian/oai/validator/examples/restassured/SwaggerValidationFilterTestExample.java (note that the example there uses WireMock to stub out a real service, but you would replace that with your actual running service).

Resources