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

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).

Related

Can I transform the input of a json inside a spring boot controller?

I have a very simple spring boot web application which consumes requests with json body.
For each json which the application will receive (from any client) I would like to manipulate it as a first step.
For example if the client sends the following body:
{
"hello": "world!!!"
}
I would like to replace each ! with a ?. In this case the result is:
{
"hello": "world???"
}
This json transformation should be valid for each controller and for any json entering the system.
Is this kind of operation possible?
Thanks.
You may use string.replace to do the same.
Or also you can add custom annotation to manipulate the values of any keys.
You can use any replacement methods or regex in your classes.
#GetMapping
public String replace(RequestItem item){
// item = item.regex/replacement method
// call your service or whatever
return item;
}
When you got the data, you can do whatever you want to do.

ClientResponse(org.springframework.web.reactive.function.client.ClientResponse) showing inconsistency across the classes while using WebClient

I have started using WebClient(org.springframework.web.reactive.function.client.WebClient) for calling rest services. I have 2 classes say Utility.java and ServiceImpl.java.
ServiceImpl.java is where I use WebClient. A post call I am making looks like -
ClientResponse response = webClient.post()
.uri(path)
.body(Mono.just(inputDTO),InputDTO.class)
.exchange()
.block();
(ClientResponse above is org.springframework.web.reactive.function.client.ClientResponse)
(I am using exchange instaed of retrive because I want headers as well as status code)
Now trying to convert this response into some DTO - ResponseDTO.
Mono<ResponseEntity<ResponseDTO>> mono = response.toEntity(ResponseDTO.class);
ResponseEntity<ResponseDTO> resEntity = mono.block();
ResponseDTO myObj = resEntity.getBody();
So myObj is an object of ResponseDTO class.
The issue is - when I perform the conversion of 'response into ResponseDTO.java' in my utility class, I get myObj = null. But if I do it in my ServiceImpl.java (just after calling post API), it returns the proper body (ResponseDTO object).
The same issue occurs even if I perform the conversion and post call operation in two different methods in the ServiceImpl.java.
Do I need to configure something here?
I figured out what was the issue.
After calling REST api, body in the response if flushed out after I read it from the response for the first time. I had a Sysout statement in service implementation class where I was reading the body content.
Recommendation: Read the body content only once and store it in a variable. Use it wherever required.

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

Spring Cloud Function with Function Routing in AWS Lambda using API Gateway

I have tried to deploy a Spring Cloud Function with multiple functions in AWS Lambda.
For HTTP access I have created an HTTP API Gateway (not a REST API). I wanted to use function routing as described here: https://cloud.spring.io/spring-cloud-static/spring-cloud-function/3.0.1.RELEASE/reference/html/spring-cloud-function.html#_function_routing.
With the following configuration, the RoutingFunction shoud deleagte the call to the correct function based on the function HTTP-Header:
spring.cloud.function.routing-expression=headers.function
The Lambda Handler class is:
org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler
and the configured function name (FUNCTION_NAME) is: functionRouter.
When I send a Request to the API-Gateway, the FunctionRouter gets a FluxJust object instead of a Message object, because the RequestHandler seems to be a Publisher.
So I get the following exception:
EL1008E: Property or field 'headers' cannot be found on object of type
'reactor.core.publisher.FluxJust' - maybe not public or not valid?:
org.springframework.expression.spel.SpelEvaluationException
org.springframework.expression.spel.SpelEvaluationException:
EL1008E: Property or field 'headers' cannot be found on object of type
'reactor.core.publisher.FluxJust' - maybe not public or not valid?
My current workaround is to intercept the request before the request is delegated to the RoutingFunction and try to reconstruct the payload from the HashMap with the following code:
#Autowired
RoutingFunction f;
#Bean
public Function<Message<LinkedHashMap>,?> router() {
return value -> {
String json = new JSONObject(value.getPayload()).toString();
Message<?> m = MessageBuilder.createMessage(json, value.getHeaders());
Object result = f.apply(m);
return result;
};
}
Is there a way proper way to use the HTTP API Gateway in combination with Function Routing in AWS?
On my project I've set function.definition and function.routing-expression like that:
spring.cloud.function.definition=functionRouter
spring.cloud.function.routing-expression=headers['pathParameters']['proxy']
This will be using the org.springframework.cloud.function.context.config.RoutingFunction that Spring Cloud Function provides and the expression would get the function name from the path.
If you still want to use the headers you could do:
spring.cloud.function.routing-expression=headers['headers']['function'].
The HTTP headers are added in the Message headers in the headers property.
So first we get the Message headers and then the HTTP headers and then the header key.

Kotlin/Spring - Fowarding post request from one service to another

We had a spring web-app that used to handle all front and back end logic. As we need to scale we have split that into two microservices. How would I go about 'forwarding' a post request to another url (including its body and authentication headers). For example:
microservice1 has an endpoint /api/doSomething
microservice2 has an endpoint /privateUrl/doSomething
I want the user to hit the endpoint on microservice1 which will post to microservice2 and return the result.
I have tried with RestTemplate without much luck, i keep getting error "Could not write JSON: No serializer found for class..." from microservice1, i suspect this is because microservice1 doesnt know how to parse the body object microservice2 requires.
microservice1:
#PostMapping("/api/DoSomething")
fun postIT(request: HttpServletRequest, #PathVariable one: String, #PathVariable two: String){ ...}
microservice2:
#CrossOrigin
#PostMapping("/privateUrl/doSomething")
fun postIT(request: HttpServletRequest, #RequestParam one: String, #RequestParam(required = false, defaultValue = "true") two: String,#RequestBody it: IT) { ... }
I know i can parse the entire request in microservice1 and then send it to microservice2, however is there a way to just 'forward' the http request to a new url?
I am not sure what you mean , but if you want to communicate from one server to another you can always use rest template (or any other) and send http request from one service to another, you can see examples here
https://www.tutorialspoint.com/spring_boot/spring_boot_rest_template.htm
https://spring.io/guides/tutorials/bookmarks/
take a look it should work for you.

Resources