How to remove unwanted keys from rest-assured response object and assert remaining object data with constant variable having json string using java - java-8

In rest-assured test cases I am getting response as mentioned, where I want to remove keys such as "updated_at", "deleted_at", "created_at" and "notice" and then assert this response object with expected json string constant which contains 'settings'
{
"notice": "The Settings are updated successfully.",
"settings": {
"push_notification": {
"enabled": true,
"credentials": [{
"key": "value"
}],
"service_name": "API Testing"
},
"created_at": "2019-05-04T14:52:32.773Z",
"deleted_at": "false",
"updated_at": "2019-05-07T11:23:22.781Z"
}
}
For given response the expected json string is...
public static String SETTING_EXPECTED = "{\"push_notification\": {\"enabled\": true, \"credentials\": [{\"key\": \"value\"}], \"service_name\": \"API Testing\"}}"
Please help me with creating a common method using java which can be reuse for response assertions in all the test cases.

To delete keys from response you can use below code I am using jayway jsonpath library, you need to pass Json Response and field name jsonPath, in case your it will be "$.settings.created_at" :
public String deleteFieldNameFromResponse(String jsonResponse, String fieldToDelete)
throws ParseException, FileNotFoundException, IOException {
Object obj = null;
JSONParser parser = new JSONParser();
JsonPath jsonPath = null;
DocumentContext docCtx = null;
obj = parser.parse(jsonResponse);
docCtx = JsonPath.parse(obj);
docCtx.delete(fieldToDelete);
jsonPath = JsonPath.compile("$");
return docCtx.read(jsonPath).toString();
}

Related

passing json in json to spring controller

I am trying to pass json object to spring controller and I manage to do that, but value of one property is in json and I think that I have problem because of it. But there is no other way to pass that data. Code is below,
data class:
#Entity
data class Section(
#Id
#GeneratedValue
val id: Long = 0L,
val name: String = "",
var text: String,
#ManyToOne
var notebook: Notebook
)
Controller code:
#PutMapping("/sections/{id}")
fun updateSection(#RequestBody section: Section, #PathVariable id: Long): Section =
sectionRepository.findById(id).map {
it.text = section.text
it.notebook = section.notebook
sectionRepository.save(it)
}.orElseThrow { SectionNotFoundException(id) }
javascript sending post to api:
function updateApi(data) {
axios.put(MAIN_URL + 'sections/' + data.id, {
data
})
.then(showChangesSaved())
.catch(ShowErrorSync());
}
function saveSection() {
var data = JSON.parse(window.sessionStorage.getItem("curr-section"));
data.text = JSON.stringify(element.editor).toString();
updateApi(data);
}
I get error like this:
2020-11-18 15:06:24.052 WARN 16172 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Instantiation of [simple type, class org.dn.model.Section] value failed for JSON property text due to missing (therefore NULL) value for creator parameter text which is a non-nullable type; nested exception is com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class org.dn.model.Section] value failed for JSON property text due to missing (therefore NULL) value for creator parameter text which is a non-nullable type
at [Source: (PushbackInputStream); line: 1, column: 375] (through reference chain: org.dn.model.Section["text"])]
so text in element.editor is JSON formatted string and I need to pass it as it is to controller. Is there any way to do that? I tried searching, but I can't find json in json help...
Whole project is available on github
What does your json looks like? If I check out your project and run the following two tests:
one with Section as an object as request body
one with Section as json
Both will succeed. So the problem might lie in your JSON:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class HttpRequestTest {
#LocalServerPort
private val port = 0
#Autowired
private val restTemplate: TestRestTemplate? = null
#Test
fun sectionAsObject() {
val section = Section(0L, "2L", "text", Notebook(1L, "1", "2"))
assertThat(restTemplate!!.put("http://localhost:$port/sections/123", section
)).isNotNull
}
#Test
fun sectionAsJson() {
val sectionAsJson = """
{
"id": 0,
"name": "aName",
"text": "aText",
"noteBook": {
"id": 0,
"name": "aName",
"desc": "2"
}
}
""".trimIndent()
assertThat(restTemplate!!.put("http://localhost:$port/sections/123", sectionAsJson
)).isNotNull
}
}
BTW: it is not a pretty good habit to expose your database ids, which is considered to be a security risk as it exposes your database layer. Instead, you might want to use a functional unique key ;)

How I can return my custom json file instead of default json file that generates spring boot?

I have a rest controller for authorization:
#RestController
class AuthController {
#PostMapping("/sign-up")
fun signUp(#RequestBody signUpRequest: SignUpRequest): ResponseEntity<String> {
some code here..
}
}
The signUp method gets SignUpRequest model as a request body. SignUpRequest model is:
enum class Role {
#JsonProperty("Student")
STUDENT,
#JsonProperty("Tutor")
TUTOR
}
data class SignUpRequest(
val role: Role,
val email: String,
val password: String
)
When I make /sign-up post request with JSON:
{
"role": "asdf",
"email": "",
"password": ""
}
It returns me an answer that were generated by spring boot:
{
"timestamp": "2020-02-12T05:45:42.387+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]\n at [Source: (PushbackInputStream); line: 3, column: 10] (through reference chain: foo.bar.xyz.model.SignUpRequest[\"role\"])",
"path": "/sign-up"
}
Question is: How I can return my custom JSON instead of that default generated JSON?
I want to return my custom JSON, like:
{
"result": "Invalid user data are given",
"errors": [
{
"fieldName": "ROLE",
"text": "Given role does not exist"
},
{
"fieldName": "EMAIL",
"text": "EMAIL is empty"
}
]
}
I suggest you to create ErrorContrller that generates custom json map as response. Then when you will catch an error in sign-up method, call ErrorContrllers method.
You can find info from this link
Finally I found out a solution. You should create a class that annotates #ControllerAdvice, and make a method that annotates #ExceptionHandler.
#ControllerAdvice
class HttpMessageNotReadableExceptionController {
#ExceptionHandler(HttpMessageNotReadableException::class)
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
fun handleException(
exception: HttpMessageNotReadableException
): PostSignUpResponseError {
val errors = mutableListOf<PostSignUpResponseErrorItem>()
errors.add(
PostSignUpResponseErrorItem(
fieldNamePost = "Role",
text = "Given role does not exist"
)
)
return PostSignUpResponseError(
result = "Invalid user data are given",
errors = errors
)
}
}
where PostSignUpResponseErrorItem and PostSignUpResponseError are:
data class PostSignUpResponseError(
val result: String,
val errors: List<PostSignUpResponseErrorItem>
)
class PostSignUpResponseErrorItem(
val fieldNamePost: PostSignUpRequestFieldName,
val text: String
)
Anyway, I still don't know how to attach this thing to a certain PostMapping method.

How to change content type for two different objectives in Spring Controller?

I am working on an API that displays JSON data and downloads CSV in one single API.
The problem is how to change Content-type of my header when I intend to download CSV file ?
Below is my code :
#RequestMapping(value = "${api.route.get.all.report}", method = RequestMethod.POST)
#PreAuthorize("hasAnyAuthority('super_admin','owner','admin')")
public ResponseEntity<?> getReportForAll(
#ApiParam("partnerId") #RequestParam(value = "partnerId", required = false) String partnerId,
#ApiParam("orgId") #RequestParam(value = "orgId", required = false) String orgId,
#ApiParam("eventId") #RequestParam(value = "eventId", required = false) String eventId,
#ApiParam("export") #RequestParam(value = "export") boolean export,
#ApiParam("Search Filter") #RequestBody SearchCriteriaDTO filterRequestDTO,
HttpServletResponse httpServletResponse) throws WazooException, IOException {
Object response = reportService.getReportsForAll(filterRequestDTO, partnerId, orgId, eventId, export,
httpServletResponse);
if (export) {
httpServletResponse.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
httpServletResponse.setHeader("Content-Disposition", "filename=" + response);
return ResponseEntity.ok(waasAppUtils.createResponseEntityDTO(HttpStatusCodes.OK,
applicationUtility.getMessage("fetched"), response));
} else {
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
return ResponseEntity.ok(waasAppUtils.createResponseEntityDTO(HttpStatusCodes.OK,
applicationUtility.getMessage("fetched"), response));
}
}
If the purpose is only to display data(when JSON data is populated), then its working as expected and I am getting following Headers :
Content-Type →application/json;charset=UTF-8
Date →Wed, 14 Mar 2018 12:27:07 GMT
Expires →0
Here is my response
{
"response_code": 200,
"response_message": null,
"response_body": [
{
"name": "",
"totalCharges": {
"platformCharge": 0.5,
"totalCharge": 0.2,
"basicCharge": 0.3
},
"id": "5a97a5930467kf42f6a2eof1"
},
All good till this point. Now the problem is, when I wish to download CSV(export flag set to true), it returns simply the file name in response body :
{
"response_code": 200,
"response_message": null,
"response_body": "/home/reports/Report_Wed Mar 14 12:26:56 UTC 2018.csv"
}
and the content-type is still displaying me "application/json;charset=UTF-8"
How can i change the content type when the flag is set to be true and display data accordingly ???
If you want to return just file in case of export, try this out:
...
if (export) {
return ResponseEntity
.ok()
.contentType(MediaType.parseMediaType("text/csv"))
.header("Content-Disposition", "filename=" + fileName)
.body(<put your file content here as byte array>);
}
...

Consuming REST Service in Spring

I'm frightfully new to Spring and Java but I'm trying to consume some code for some rule validations in Easy Rules but I can't quite figure it out.
#RequestMapping(method = {RequestMethod.GET}, value = "author/field", produces= MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<Enum> getField(#RequestParam(value="field", required=true) String field){
Enum enum = mongoService.findByField(field);
if(enum == null){
return new ResponseEntity<Enum>(HttpStatus.NO_CONTENT);
}else{
return new ResponseEntity<Enum>(enum,HttpStatus.OK);
}
}
So I'm trying something like:
import com.mongoservice.Enum
import com.mongoservice.Enums
RestTemplate restTemplate = new RestTemplate();
String uri = "http://localhost:9000";
//This is my confusion
List<Enums> response = restTemplate.getForObject(uri +
"/author/field?={field}", Enum.class,"a").getEnums();
String value = response.getValue().toString().trim();
//this is the record i'm checking against that is pulling a specific string value and what i'm expecting
String record = "a";
return (value == record);
The JSON data I'm trying to pull back is modeled like this but I need to validate to make sure that record equals one of the values from enums[] json array
{
"field": "a",
"descriptor": "blah",
"enums": [
{
"value": "h",
"description": "blah"
},
{
"value": "e",
"description": "blah"
},
{
"value": "l",
"description": "blah"
},
{
"value": "p",
"description": "blah"
}
]
}
What is the problem that you are seeing is it just not matching? If so it could be because you are using == instead of String.equals. Try modifying your code to:
return record.equals(value);
See Java String.equals versus == for more.
Can you change String uri = "http://localhost:9000"
and missed the path variable name field it should be like author/field?field={field} as per your controller description.

How do i send JsonObject with nested values as Post request in REST assured

I am using rest assured -https://code.google.com/p/rest-assured/wiki/Usage
My JsonObject looks like this
{
"id": "12",
"employeeInfo": null,
"employerInfo": null,
"checkDate": 1395093997218,
"netAmount": {
"amount": 70,
"currency": "USD"
},
"moneyDistributionLineItems": [
{
"mAmount": 100,
"employeeBankAccountId": "BankAccount 1"
}
],
}
how can i send this as part of parameters using REST-assured POST?
I have tried
given().param("key1", "value1").param("key2", "value2").when().post("/somewhere").then().
body(containsString("OK"));
but that is not scalable for HUGE objects with nested values. Is there a better approach?
You just send the JSON document in the body. For example if you have your JSON document in a String called myJson then you can just do like this:
String myJson = ..
given().contentType(JSON).body(myJson).when().post("/somewhere"). ..
You can also use a POJO, input stream and byte[] instead of a String.
URL file = Resources.getResource("PublishFlag_False_Req.json");
String myJson = Resources.toString(file, Charsets.UTF_8);
Response responsedata = given().header("Authorization", AuthorizationValue)
.header("X-App-Client-Id", XappClintIDvalue)
.contentType("application/vnd.api+json")
.body(myJson)
.with()
.when()
.post(dataPostUrl);

Resources