RestAssured: How to validate response body with JSON schema if response body has extra values? - rest-assured

I am validating json schema using matchesJsonSchemaInClasspath. It is working fine if response body have the same values that are defined in schema.json file.
If response body have EXTRA variable / value which is not define in json schema then it does not fail. How to fail this test case?
FOR EXAMPLE:
Below is response body which has predefined JSON schema.
{
"employee": {
"name": "sonoo",
"salary": 56000,
"married": true
}
}
If response body gives extra values such as email / phone then it is still passing. I need to make it fail.This is my test case to fail if response body return extra value. How to validate this test case?
{
"employee": {
"name": "Mike",
"salary": 56000,
"Phone": "+XXX",
"email": "test#gmail.com",
"married": true
}
}

Create a POJO class representing the json
public class Employee {
private String name;
private float salary;
private boolean married;
// Getter Methods
public String getName() {
return name;
}
public float getSalary() {
return salary;
}
public boolean getMarried() {
return married;
}
// Setter Methods
public void setName(String name) {
this.name = name;
}
public void setSalary(float salary) {
this.salary = salary;
}
public void setMarried(boolean married) {
this.married = married;
}
}
Use the following rest assured command to deserialize the response
Employee emp = response.getBody().as(Employee.class);
The above command will automatically fail and throw an error when additional field such as email or phone number is added to response body.

Related

Jackson Object mapper how to Serialize object as String which is having nested object?

I have json like following
{"data": [
{
"instance": { ...
"inner"" {....
.............}
}
}]
"isvalid":true
"nextVal" : <some num>
}
and POJO like
class A{
private String data;
private boolean isvalid;
private String nextVal;
//with getter setters and proper jackson annotations
}
These can have variable structure inside data, so with object mapper.read I want to take entire data object in string!
have tried direct serialization to my simple object which obviously gives error and also tried JSONNode
mapper.readValue(jsonString, JsonNode.class);
String content = node.get("data").textValue();
This returns blank
anyway I can achieve that to take entire data object value in string with objectmapper?
I tried toString and returned just fine what I wanted - entire data object as String
JsonNode node = (ObjectNode) mapper.readValue(jsonString, JsonNode.class);
node.get("data").toString();
The reason it returns blank is because, data is an array. You need to deseralise it in to JsonArray. Assuming your JSON structure as below,
{
"data": [
{"instance": {
"inner": {
"id": "1"
}
}
}],
"isvalid": true,
"nextVal": 1
}
This will be deserialised using below code (in JSONNode),
List<JsonNode> list = node.findValues("data");
for(JsonNode n: list){
JsonNode in1 = n.findValue("instance");
JsonNode in2 = in1.findValue("inner");
String abc = in2.findValue("id").textValue();
System.out.println(abc);
}
You need to have the POJO structure as shown above. The data will be list of instance object. instance object will have to have inner object.
Update:
Outer node = mapper.readValue(jsonstr, Outer.class);
The classes which needs to be created would be as shown below.
public class Outer {
private List<Data> data;
Boolean valid;
Integer nextval;
public List<Data> getData() {
return data;
}
public void setData(List<Data> data) {
this.data = data;
}
public Boolean isValid() {
return valid;
}
public void setValid(Boolean valid) {
this.valid = valid;
}
public Integer getNextval() {
return nextval;
}
public void setNextval(Integer nextval) {
this.nextval = nextval;
}
}
public class Data {
Instance instance;
public Instance getInstance() {
return instance;
}
public void setInstance(Instance instance) {
this.instance = instance;
}
}
public class Instance {
private Inner inner;
public Inner getInner() {
return inner;
}
public void setInner(Inner inner) {
this.inner = inner;
}
}
public class Inner {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

How to customize the built-in MVC validation response format?

I'm using my own middleware to capture exceptions thrown in my API to format the response to the client. This includes things like checking for the dev env to send additional information and logging. This all works great but the built-in validation middleware responds with a different response format. I want to keep the functionality and just change what data is sent to the client and how it's formatted.
Currently it returns the default
{
"message": "Validation error(s)",
"details": [
"The value '35353535353535353535353535353535353535353535' is not valid."
]
}
You can customize the default response by using a BadResultObject in the InvalidaModelStateResponseFactory of the ApiBehaviorOptions class. As an example:
apiBehaviorOptions.InvalidModelStateResponseFactory = actionContext => {
return new BadRequestObjectResult(new {
Code = 400,
Request_Id = "Someuniqueid",
Messages = actionContext.ModelState.Values.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage)
});
Configured:
serviceCollection.PostConfigure<ApiBehaviorOptions>(apiBehaviorOptions =>
apiBehaviorOptions.InvalidModelStateResponseFactory = ...
);
Or you can send the response directly from the action you are using as well with your own custom validation error result class. For example:
public class ValidationError
{
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public string Field { get; }
public string Message { get; }
public ValidationError(string field, string message)
{
Field = field != string.Empty ? field : null;
Message = message;
}
}
public class ValidationResultModel
{
public string Message { get; }
public List<ValidationError> Errors { get; }
public ValidationResultModel(ModelStateDictionary modelState)
{
Message = "Validation Failed";
Errors = modelState.Keys
.SelectMany(key => modelState[key].Errors.Select(x => new
ValidationError(key, x.ErrorMessage)))
.ToList();
}
}
Then we can create our own IActionResult. Here:
public class ValidationFailedResult : ObjectResult
{
public ValidationFailedResult(ModelStateDictionary modelState)
: base(new ValidationResultModel(modelState))
{
StatusCode = StatusCodes.Status404...;
}
}
And update our ValidateModelAttribute by overriding the OnActionExecuting to perform actions before they are taken.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
context.Result = new ValidationFailedResult(context.ModelState);
}
}
}
Sources:
Customize automatic response on validation error
https://www.jerriepelser.com/blog/validation-response-aspnet-core-webapi/

How do you send XML post request using rest-assured?

I have to send a post request with xml data and then validate the response like example checking the status code and response body.
You can either pass a pojo (remember to set the content-type to application/xml) and rest assured will automatically transform it into XML. For example:
#XmlRootElement
public class Greeting {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
and then you can use it like this:
Greeting greeting = new Greeting();
greeting.setFirstName("John");
greeting.setLastName("Doe");
given().contentType(ContentType.XML).and().body(object).when().post("/somewhere"). ..
it'll send the following XML:
<greeting>
<firstName>John</firstName>
<lastName>Doe</lastName>
</greeting>
Let's say that the server is responding with the same XML as the one you see above then you can validate the response status code and body like this:
given().
contentType(ContentType.XML).
body(object).
when().
post("/somewhere").
then().
statusCode(200).
body("greeting.firstName", equalTo("John")).
body("greeting.lastName", equalTo("Doe"));
REST Assured will automatically understand the the response body is XML if the server returns an XML content-type. Note that equalTo is statically imported from org.hamcrest.Matchers#equalTo.

Allow empty string for EmailAddressAttribute

I have property in my PersonDTO class:
[EmailAddress]
public string Email { get; set; }
It works fine, except I want to allow empty strings as values for my model, if I send JSON from client side:
{ Email: "" }
I got 400 bad request response and
{"$id":"1","Message":"The Email field is not a valid e-mail address."}
However, it allows omitting email value:
{ FirstName: "First", LastName: 'Last' }
I also tried:
[DataType(DataType.EmailAddress, ErrorMessage = "Email address is not valid")]
but it does not work.
As far as I understood, Data Annotations Extensions pack does not allow empty string either.
Thus, I wonder if there is a way to customize the standard EmailAddressAttribute to allow empty strings so I do not have to write custom validation attribute.
You have two options:
Convert string.Empty to null on the Email field. Many times that is perfectly acceptable. You can make this work globally, or by simply making your setter convert string.Empty to null on the email field.
Write a custom EmailAddress attribute, since EmailAddressAttribute is sealed you can wrap it and write your own forwarding IsValid method.
Sample:
bool IsValid(object value)
{
if (value == string.Empty)
{
return true;
}
else
{
return _wrappedAttribute.IsValid(value);
}
}
Expansion on option 1 (from Web Api not converting json empty strings values to null)
Add this converter:
public class EmptyToNullConverter : JsonConverter
{
private JsonSerializer _stringSerializer = new JsonSerializer();
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
string value = _stringSerializer.Deserialize<string>(reader);
if (string.IsNullOrEmpty(value))
{
value = null;
}
return value;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
_stringSerializer.Serialize(writer, value);
}
}
and use on the property:
[JsonConverter(typeof(EmptyToNullConverter))]
public string EmailAddress {get; set; }
or globally in WebApiConfig.cs:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(
new EmptyToNullConverter());
It's Easy. Do This. Bye
private string _Email;
[EmailAddress(ErrorMessage = "Ingrese un formato de email vĂ¡lido")]
public string Email { get { return _Email; } set { _Email = string.IsNullOrWhiteSpace(value) ? null : value; } }
I used the suggestion from Yishai Galatzer to make a new ValidationAttribute called EmailAddressThatAllowsBlanks:
namespace System.ComponentModel.DataAnnotations
{
public class EmailAddressThatAllowsBlanks : ValidationAttribute
{
public const string DefaultErrorMessage = "{0} must be a valid email address";
private EmailAddressAttribute _validator = new EmailAddressAttribute();
public EmailAddressThatAllowsBlanks() : base(DefaultErrorMessage)
{
}
public override bool IsValid(object value)
{
if (string.IsNullOrEmpty(value.ToString()))
return true;
return _validator.IsValid(value.ToString());
}
}
}
Set TargetNullValue property of the binding to an empty string.
TargetNullValue=''

Return multiple objects using Json.Net

With the built-in json converter I return multiple objects in my action like this:
return Json(new { success = true, data = units });
When I use the JSON.NET library how can I do the same?
This does obviously not compile:
return new { success = true, data = JsonConvert.SerializeObject(units) };
I do not want to create an extra viewmodel for this containing both properties.
Do I have a wrong understanding of the default Json javascript serializer maybe ?
If you want to use Newtonsoft.Json to serialise your objects, you can create a new ActionResult class and pass the data in the result.
For example:
public class NewtonsoftJsonResult : ContentResult
{
private readonly object _data;
public NewtonsoftJsonResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
Content = JsonConvert.SerializeObject(_data);
ContentType = "application/json";
base.ExecuteResult(context);
}
}
Just return your custom ActionResult with the anonymous object as data:
public ActionResult Index()
{
return new NewtonsoftJsonResult(new { success = true, data = units});
}
In your second example, JsonConvert.SerializeObject(units) will result in a string returned to JavaScript. JavaScript won't see data as containing some "real" data but rather a simple string, with curly parentheses inside.
Use your first sentence as usual. MVC's Json method will serialize the objects within.
For example:
class Units
{
public int Width { get; set; }
public int Height { get; set; }
}
...
Units u = new Units { Width = 34, Height = 20 };
return Json(new { success = true, data = units });
will result in a Json that looks similar to this:
{ "success" : "true", "data" : { "Height" : "20", "Width" : "34" } } }

Resources