ValidationException errors in errors - json

In grails 2.3, I want to send customized error message by JSON. But when I use
class ApiError {
String message
String status
Exception error
}
and try to parse it as JSON I get: (I ommit irrevelant message and status)
"error": {
"cause": null
"class": "grails.validation.ValidationException"
"errors": {
"errors": [1]
0: {
"object": "com.example.Firm"
"field": "context"
"rejected-value": null
"message": "Property [context] of class [class com.example.Firm] cannot be null"
}
}
"localizedMessage": "Firm is not valid: - Field error in object 'com.example.Firm' on field 'context': rejected value [null]; codes [com.example.Firm.context.nullable.error.com.example.Firm.context,com.example.Firm.context.nullable.error.context,com.example.Firm.context.nullable.error.java.lang.String,com.example.Firm.context.nullable.error,firm.context.nullable.error.com.example.Firm.context,firm.context.nullable.error.context,firm.context.nullable.error.java.lang.String,firm.context.nullable.error,com.example.Firm.context.nullable.com.example.Firm.context,com.example.Firm.context.nullable.context,com.example.Firm.context.nullable.java.lang.String,com.example.Firm.context.nullable,firm.context.nullable.com.example.Firm.context,firm.context.nullable.context,firm.context.nullable.java.lang.String,firm.context.nullable,nullable.com.example.Firm.context,nullable.context,nullable.java.lang.String,nullable]; arguments [context,class com.example.Firm]; default message [Property [{0}] of class [{1}] cannot be null] "
"message": "firm is not valid: - Field error in object 'com.example.Firm' on field 'context': rejected value [null]; codes [com.example.Firm.context.nullable.error.com.example.Firm.context,com.example.Firm.context.nullable.error.context,com.example.Firm.context.nullable.error.java.lang.String,com.example.Firm.context.nullable.error,firm.context.nullable.error.com.example.Firm.context,firm.context.nullable.error.context,firm.context.nullable.error.java.lang.String,firm.context.nullable.error,com.example.Firm.context.nullable.com.example.Firm.context,com.example.Firm.context.nullable.context,com.example.Firm.context.nullable.java.lang.String,com.example.Firm.context.nullable,firm.context.nullable.com.example.Firm.context,firm.context.nullable.context,firm.context.nullable.java.lang.String,firm.context.nullable,nullable.com.example.Firm.context,nullable.context,nullable.java.lang.String,nullable]; arguments [context,class com.example.Firm]; default message [Property [{0}] of class [{1}] cannot be null] "
"stackTrace": [...143]
"suppressed": [0]
}
I do not understand; what's the point of using errors array in errors? And how to get only one errors array?
Here is a source code of this class.

Grails validation errors contain both global errors and field errors. Whenever validation exception occurs in grails, it doesn't throw a new exception for each field error, rather it wraps all field errors inside a single Error object. There may be global object errors, a global reason for rejecting an object.
So if you want to avoid errors inside errors then you should modify your ApiError class by replacing Exception error with List<Errors> errors and setting its value from instance.errors.
Or you can use a custom method to parse errors:
CodecLookup codecLookup
protected List retrieveErrors(instance) {
CodecLookup codec = Holders.applicationContext.getBean(CodecLookup)
List errors = []
g.eachError([bean: instance], {
error ->
errors.add(codec.lookupDecoder('HTML').decode(g.message(error: error)))
})
return errors
}
g is the namespace for ValidationTagLib that is available in each controller.

Related

Why CodeMirror throws error client.js:230 TypeError: string.split is not a function when I try to set the value for it?

I am trying to set the JSON value for the CodeMirror editor but it throws the error: client.js:230 TypeError: string.split is not a function.
I am trying to set the value which is coming from the server when I make the POST request and the value is a JSON document but the server is returning it as a text/plain. When I make the server to return application/json then everything works fine, but when I change it to text/plain then it throws the error:
client.js:230 TypeError: string.split is not a function
at splitLinesAuto (codemirror.js:685:41)
at Doc.splitLines (codemirror.js:6531:14)
at Doc.eval (codemirror.js:6184:36)
at Doc.eval [as setValue] (codemirror.js:3986:22)
at CodeMirror.eval [as setValue] (codemirror.js:9832:40)
at VueComponent.$storeStateModulesOutputStoreMyOutput (index.js?!./node_modules/vue-loader/lib/index.js?!./pages/OutputView.vue?vue&type=script&lang=js&:137:35)
at invokeWithErrorHandling (vue.runtime.esm.js:3026:30)
at Watcher.run (vue.runtime.esm.js:3542:21)
at flushSchedulerQueue (vue.runtime.esm.js:4129:17)
at Array.eval (vue.runtime.esm.js:3152:20)
I am bit confused why its unable to set the value for data when returned as text/plain but works fine when returned as application/json.
The data is coming properly and able to see the value just before I am setting it:
'$store.state.modules.OutputStore.myOutput' (value) {
console.log('Returned Output : ' + JSON.stringify(value, null, 4)) //able to see the json document value properly
this.outputEditor.setValue(value) //throwing the error here
}
The example json file looks something like this:
{
"isA": "customerDocument",
"createdOn": "2022-10-10T12:29:43",
"customerBody": {
"customerList": [
{
"name": "Batman",
"age": 45,
"city": "gotham"
},
{
"name": "superman",
"age": 50,
"city": "moon"
}
]
}
}
The same code works fine when the server returns application/json. I do not understand if the value is coming then shouldnt it set in code mirror?

Why is my Netlify function throwing an error trying to JSON.parse() the event object?

I am trying to implement SendGrid through a Netlify serveless functions, however every time after submitting the form the function throws this error:
{
"errorType": "SyntaxError",
"errorMessage": "Unexpected token a in JSON at position 1",
"trace": [
"SyntaxError: Unexpected token a in JSON at position 1",
" at JSON.parse (<anonymous>)",
" at Runtime.exports.handler (/var/task/src/functions/sendmail.js:5:44)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]
}
I have no idea what is wrong as from Netlify docs the event.body is a JSON string so why JSON.parse() is not working?
Github

Wrapping default REST error response in custom object

I'm building a simple REST api for integration purposes, and i want the response to be as consistent as possible (the same regardless of errors).
I've used the #ExceptionHandler method in the past - so I'll most likely go with the class version of this...#ControllerAdvice if i remember correctly.
I know it works, I've used SO before to help me, it just requires setting up. This is not my question...
The API allows creating messages and searching messages (two separate requests), and thus, accepts date values which are internally validated. Upon testing this i received a really nicely formatted and incredibly detailed error response:
{
"timestamp": "2018-08-31T10:35:10.748+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"typeMismatch.IntegrationMessageFilter.fromDate",
"typeMismatch.fromDate",
"typeMismatch.java.util.Date",
"typeMismatch"
],
"arguments": [
{
"codes": [
"IntegrationMessageFilter.fromDate",
"fromDate"
],
"arguments": null,
"defaultMessage": "fromDate",
"code": "fromDate"
}
],
"defaultMessage": "Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'fromDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [#com.fasterxml.jackson.annotation.JsonFormat java.util.Date] for value '213-456-45'; nested exception is java.lang.IllegalArgumentException",
"objectName": "IntegrationMessageFilter",
"field": "fromDate",
"rejectedValue": "213-456-45",
"bindingFailure": true,
"code": "typeMismatch"
}
],
"message": "Validation failed for object='IntegrationMessageFilter'. Error count: 1",
"path": "/Integration/get"
}
What i want to do is intercept this error and wrap it in my own response object which will be the same response object for every API method available:
e.g.
{
"success": Boolean,
"messageId": Integer, (null on search, int on successful create)
"messages": Array, (searched IntegrationMessage objects)
"errorMessage": String, (error message during manual validation (e.g. range validation depending on the field))
"error" [SPRING DEFAULT ERROR] (this is what i want to intercept from spring-boot and include in this response object)
}
It just sees a bit pointless to manually faff about creating a detailed error message when the system does it already...I don't know what object it uses to create the first JSON message above, or even if i can intercept it.
NOTE: This is purely for the convenience of the API users not having to differentiate between different response objects, and the convenience for me, not having to re-develop the wheel (so to speak).
OK so I've found how to acheive (sort of) what i want.
I was under the impression i could intercept the full exception response message and just put it inside my object, regardless of the type of exception. Turns out, i can get most of the default information, but it is specific to each error type (obviously).
First Attempt:
My first attempt was to simply "test" the default error response with the following. This was meant to identify what spring was doing (which error it was using - I genuinly thought it would have been the handleTypeMismatch exception) - the method below is just one in the class (the one that I'm currently dealing with):
#ControllerAdvice
public class IntegrationExceptionHandler extends ResponseEntityExceptionHandler
{
#Override
public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
{
return super.handleBindException(ex, headers, status, request);
}
}
I expected exactly the same error message as the default one, however this produced no response (or an empty response?).
My "Solution":
While i don't have to re-develop the wheel, i do have to do some hoop jumping:
#Override
public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
{
IntegrationResponse response = new IntegrationResponse(ex.getMessage());
response.setErrors(ex.getBindingResult().getAllErrors());
return new ResponseEntity<Object>(response, headers, status);
}
Where errors is private List<ObjectError> errors; (org.springframework.validation.ObjectError)
So I'll have to try and replicate each overridable error in the ResponseEntityExceptionHandler (that applies to my situation) and treat it slightly differently, you can see now why i just wanted to wrap the existing response.
Just as a side note, I did try adding: private Object error; and private BindingResult error; as variables in my response object, however both attempts seem to reject my response object and show JUST the default message (as if there is no controller advice) with no hint as to why.
If anyone does discover how to skip the ResponseEntityExceptionHandler step and just wrap the default exception response object, I'll happily accept that answer.

Postman: More descriptive tv4 validation error message

I'm using postman to validate the schema of json data returned from an api.
I have a test that runs through basic http validation, then ends with:
if (tv4.error){
console.log("Validation failed: ", tv4.error);
}
The error I get back is difficult to fathom.
Validation failed: 12:22:41.316
Object:{}
message:"Invalid type:
number (expected string)"
name:"ValidationError"
type:"Error"
But I need to know which field the validation failed on. How can I get this info? The npm page for tv4 suggests that the error message should be more descriptive.
According to the documentation of tv4, you can print the path of the error location using console.log(tv4.error.dataPath), I have no idea why this attribute is not logged in the console.
Documentation is here.
The relevant section in the documentation is:
If validation returns false, then an explanation of why validation failed can be found in tv4.error.
The error object will look something like:
{
"code": 0,
"message": "Invalid type: string",
"dataPath": "/intKey",
"schemaPath": "/properties/intKey/type"
}

Rally JSON I/O error creating a test case result

I am trying to create a test case result using a REST client, but get this error:
"Errors": ["Cannot parse input stream due to I/O error as JSON document: Parse error: expected '{' but saw '\uFFFF' [ chars read = >>>\uFFFF<<< ]"]
I get the same error when the name of the object, testcaseresult is not specified in the request body. Here are the steps to create a test case result using a browser REST client:
a) Generate the authorize key using "GET" method and the following URL:
https://rally1.rallydev.com/slm/webservice/v2.0/security/authorize
This is the response that I get back, with the security token: "123abc..."
{"OperationResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": [], "Warnings": [], "SecurityToken": "abc123..."}}
b) Use "POST" method, and the following URL:
https://rally1.rallydev.com/slm/webservice/v2.0/testcaseresult/create?key=abc123...
notice the security token in the end.
c) here is an example of a request body:
{
"testcaseresult":
{
"Build":"1",
"Tester":"/user/777",
"Date":"2010-09-04T19:56:05.000Z",
"TestCase":"/testcase/1111",
"Verdict":"Pass"
}
}
Only the required fields and the fields you want to set need to be referenced. Notice the outer key/value pair
{
"testcaseresult":{}
}
The fields that point to a full object, like "Tester" (points to User object) and "TestCase" (points to a TestCase object that owns the result) have to be referenced by their ObjectIDs:
"Tester":"/user/777",
"TestCase":"/testcase/1111",