can someone please assist, I'm using restassured to pull and display results from this server https://jsonplaceholder.typicode.com/posts/9/comments, but cannot verify the emails of this user and display accurate data. Here is my code below:
public static void getPostComments() {
System.out.println("===============Comments By User==================");
given().when().get(url + "/posts/9/comments").then().log()
.body();
Response res = given().when().get(url + "/posts/9/comments");
List<String> jsonRes = res.jsonPath().getList("email");
if (jsonRes.equals("Lucio#gladys.tv")) {
given().queryParam("id", "9")
.get("http://localhost:3000/posts/9/comments/")
.then()
.assertThat()
.body("email["+String.valueOf(0)+"]", Is.is("Lucio#gladys.tv"))
.log()
.body();
}
}
The results I get from the above code, just returns all the users without validating. I'm fairly new to restassured, but would appreciate any pointers to validate these emails.
There are many ways to do that.
Example 1:
given()
.get("https://jsonplaceholder.typicode.com/posts/9/comments")
.then()
.assertThat()
.body("email", hasItem("Lucio#gladys.tv"));
Example 2:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
List<String> emails = given()
.get("https://jsonplaceholder.typicode.com/posts/9/comments")
.jsonPath()
.get("email");
assertThat(emails, hasItem("Lucio#gladys.tv"));
Related
I'm new using webclient to cosume a Rest API and I want to know how can I filter a response to match only what I want.
So I have this endpoint which brings me a customerById but I need to show only the the systemsId = 100
Let me show:
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class);
}
And the POJO:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CuCoPerson {
private Integer cucoID;
private List<CustomerRelation> relatedCustomers;
}
And this is the response in Postman:
{
"cucoID": 100288298,
"relatedCustomers": [
{
"customerId": "F6305957",
"systemId": 100
},
{
"customerId": "F8364917",
"systemId": 400
},
{
"customerId": "F4194868",
"systemId": 101
}
]
}
So I need only to show the relatedCustomers who only have a systemID = 100
Thanks in advance!
I think you are looking for either Mono.map(), or Mono.flatMap().
Remove the customers, who don't match in the function, and return the changed object.
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(100))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
As mentioned in other answers, doing this kind of filtering on client side is bad practice. If possible the API should expose parameter for systemId and return only the data you need.
First of all this is bad Backend design. Since you (client side) have the need for such info you should have an endpoint available to get your info by customer ID and System ID. Data filtering should be done on the backend and the client should remain as thin as possible. Otherwise you perform logic both on server-side and client-side plus you send some completely unneeded info over the network and then filter it out on the client side. But if that's your available resources and you can't change the server-side then you you take your JSON response, and parse it into your class that maps to that JSON or just into Map<String,Object> if you don't have the class for that JSON and filter it out yourself. To parse a json string to map or a specific POJO you can use Jackson library - method readValue() of ObjectMapper Or Gson library. Also, I wrote my own simple wrapper over Jackson library that simplifies the use. Class JsonUtils is available as part of MgntUtils library (written and maintained by me). This class just has the methods that allow you to parse and de-serialize from/to Json String from/to a class instance. Here is a simple example on how to parse your JSON string into a Map<String,Object> with JSONUtils class
Map<String,Object> myMap
try {
myMap = JsonUtils.readObjectFromJsonString(myJsonStr, Map.class);
} catch(IOException ioe) {
....
}
MgntUtils library available as Maven artifact and on Github (including source code and Javadoc)
it could be something like this:
return webClient.get()
.uri("/someUrl")
.header("Accept", "application/json")
.header("Authorization", "Bearer eyJraWQiOi.....")
.retrieve()
.bodyToFlux(CuCoPerson.class)
.filter(cuCoPerson -> cuCoPerson.getRelatedCustomers().stream().anyMatch(cr -> cr.getSystemId() == 100))
.take(1)
.next();
But this has disadvantage that you are filtering the results on client side (your application). I would try to ask the api provider if s/he is able to provide filter parameter (something like systemId) and in that case you would call the endpoint with that query param.
I have a Quarkus application with the following filters definition:
#ApplicationScoped
#Slf4j
public class Filters {
// some #Inject parameters i'm using
#ServerRequestFilter(preMatching = true)
public void requestLoggingFilter(ContainerRequestContext requestContext) {
log.info("Recv: [{}] {}, {}", requestContext.getHeaderString("myHeader"), requestContext.getMethod(), requestContext.getUriInfo().getRequestUri());
}
#ServerResponseFilter
public void responseBasicHeaderFilter(ContainerResponseContext responseContext) {
responseContext.getHeaders().putSingle("myHeader, "myValue");
}
#ServerResponseFilter
public void responseLoggingFilter(ContainerResponseContext responseContext) {
log.info("Sent: [{}] {} {}", responseContext.getHeaderString("myHeader"), , responseContext.getStatusInfo(), responseContext.getEntity());
}
}
And I have two tests:
Test Class config:
#QuarkusTest
public class MyTest {
...
}
Test A:
final Response response = given()
.post(BASE_URL)
.then()
.extract().response();
assertEquals(200, response.getStatusCode(), () -> "Got: " + response.prettyPrint());
assertEquals("myValue", response.getHeader("myHeader"));
final Response response2 = given()
.get(BASE_URL)
.then()
.extract().response();
assertEquals(200, response2.getStatusCode(), () -> "Got: " + response2.prettyPrint());
assertEquals("myValue", response2.getHeader("myHeader"));
Test B:
final Response response = given()
.post(BASE_URL)
.then()
.extract().response();
assertEquals(200, response.getStatusCode(), () -> "Got: " + response.prettyPrint());
assertEquals("myValue", response.getHeader("myHeader"));
If i run Test B on it's own, it passes.
If i run Test A however the last assertion fails (the header value is not there).
The #ServerResponseFilter seem to not be called beyond the first time, however #ServerRequestFilter seem to be fine.
I have tested the api manually and can confirm the same behaviour. Calling the GET request first will also have the same behaviour.
I have verified that the response generated by my Controller (pojo) is generated successfully.
What could be preventing it from being rerun?
Turns out it wasn't related to GET vs POST
my GET method was returning a Multi . I converted this to Uni> and it worked.
From the documentation i found this snippet
Reactive developers may wonder why we can't return a stream of fruits directly. It tends to eb a bad idea with a database....
The keyword being we can't so I imagine this is not supported functionality
I'm trying to call an get api which is hosted in aws api gateway via rest-assured
I'm able to sign the request and make a call. But to sign the request, I need to pass the full url to AWS to generate the Authorization Header.
For Ex. If I'm going to access an an endpoint
https://my-aws-api.com/basepath/v1/request/123
I need to sign the request via AWSSigner which needs the full endpoint to do so.
My current approach
String baseURI="https://my-aws-api.com";
String basePath="basepath/v1";
String requestPath="request/123";
String endpoint=baseURI+"/"+basePath+"/"+requestPath;
Map<String,String> signedHeaders= aws4sign(endpoint,defaultHeaders);
given()
.log().ifValidationFails()
.headers(signedHeaders)
.when()
.get(endpoint)
.then()
.log().ifValidationFails()
.statusCode(200);
If I do that , then I cant use RestAssured's baseURI, basePath and path params
I want to access it like
RestAssured.baseURI="https://my-aws-api.com";
RestAssured.basePath="basepath/v1";
given()
.log().ifValidationFails()
.pathParam("reqID", "123")
.when()
.get("request/{reqID}")
.then()
.log().ifValidationFails()
.statusCode(200);
AwsSigner
public static Map<String, String> aws4Sign(String endpoint, Map<String, String> headers) throws URISyntaxException {
String serviceName = "execute-api";
AWS4Signer aws4Signer = new AWS4Signer();
aws4Signer.setRegionName(EU_WEST_1.getName());
aws4Signer.setServiceName(serviceName);
DefaultRequest defaultRequest = new DefaultRequest(serviceName);
URI uri = new URI(endpoint);
defaultRequest.setEndpoint(new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "", "", ""));
defaultRequest.setHttpMethod(HttpMethodName.GET);
defaultRequest.setResourcePath(uri.getRawPath());
defaultRequest.setHeaders(headers);
aws4Signer.sign(defaultRequest, DefaultAWSCredentialsProviderChain.getInstance().getCredentials());
return defaultRequest.getHeaders();
}
So My question is there any way, I can intercept the RestAssured's request before it makes the call, so that I can get the fully generated end point and add the aws signed header to the call.
I am not familiar with this library but from briefly reading its documentation and Javadoc, you should be able to use a RequestFilter to inspect and alter a request before it is sent out.
Take a look at the Filter section of the user guide.
Thanks to #Ashaman.
The Filter Section is what I'm looking for
You can get the uri and other headers that were passed with requests from RequestSpec and then send it to the function to sign them and remove the old headers and put the new headers. Then forward the request
#BeforeAll
public void init() {
RestAssured.baseURI = "https://my-aws-api.com";
RestAssured.filters((requestSpec, responseSpec, ctx) -> {
Map<String, String> headers = requestSpec.getHeaders()
.asList()
.stream()
.collect(Collectors.toMap(Header::getName, Header::getValue));
Map<String, String> signedHeaders = aws4sign(requestSpec.getURI(), headers);
requestSpec.removeHeaders();
requestSpec.headers(signedHeaders);
return ctx.next(requestSpec, responseSpec);
});
}
And for the tests I can use the features of Rest Assured normally
given()
.log().ifValidationFails()
.pathParam("reqID", "123")
.when()
.get("request/{reqID}")
.then()
.log().ifValidationFails()
.statusCode(200);
I have more than two similar REST ASSURED rests e.g.
#Test
public void makeSureThatGoogleIsUp() {
given().auth().oauth2(getToken()).contentType("application/json")
.when()
.get("http://www.google.com")
.then()
.statusCode(200);
}
#Test
public void makeSureThatGoogleIsUp() {
given().auth().oauth2(getToken()).contentType("application/json")
.when()
.get("https://stackoverflow.com")
.then()
.statusCode(200);
}
And I would've like to create method called given() to make method less complex and readable.
private [something] given(){
return given().auth().oauth2(getToken()).contentType("application/json")
}
making my methods use my given instead of rest assured one:
#Test
public void makeSureThatGoogleIsUp() {
given()
.when()
.get("http://www.google.com")
.then()
.statusCode(200);
}
#Test
public void makeSureThatGoogleIsUp() {
given()
.when()
.get("https://stackoverflow.com")
.then()
.statusCode(200);
}
something like here: but I dont really know what kind of return type this method could have or if its even possible.
Sorry, question can be trival, but seriously I'm stuck here.
Any helps? Thanks! :)
It returns a RequestSpecification object: http://static.javadoc.io/com.jayway.restassured/rest-assured/2.4.1/com/jayway/restassured/specification/RequestSpecification.html
Also a side note if you're creating your own given() -- it might be better to name the method something else as someone else using it might assume it's the jayway version and confuse themselves when they get errors.
I am using the following code for making the service call using the Rest assured library, can you help me to resolve the build issues. There is a problem in finding the function "equalTo" to validate the response data.
See error below:
Here is my code:
#Test
public void testFileUpload() {
final File file = new File(getClass().getClassLoader()
.getResource("test.txt").getFile());
assertNotNull(file);
assertTrue(file.canRead());
given()
.multiPart(file)
.expect()
// problem here
.body(equalsTo("This is an uploaded test file."))
.when()
.post("/service/file/upload");
}
#Test
public void testGetSingleUser() {
given()
.expect()
.statusCode(200)
.body(
"email", equalTo("test#hascode.com"),
"firstName", equalTo("Tim"),
"lastName", equalTo("Testerman"),
"id", equalTo("1"))
.when()
.`enter code here`
.get("/service/single-user");
}
I assume it is the equalTo from the hamcrest library.
Can you add this import and see if it works
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.equalTo;
With adding above hamcrest library, Error will be resolved.
I have tried and it worked.
Import this Line you will get the equalTo()
import static org.hamcrest.Matchers.*;