How to handle errors from custom business entity in KUIB

Posted by jts-law on 19-May-2017 11:27

Has anybody implemented custom errors within a business entity and figured out how to display them in KUIB?

I have a very custom business entity object with many rules that allow/deny create/delete/update of records.  In each case where an action is denied I'm setting ERROR and REJECTED on the before temp-table records and/or the after temp-table records.  I'm also setting the ERROR-STRING and then calling REJECT-CHANGES on the dataset.  None of this generates an error message on the KUIB app.

Also, in case this comes into play, my business entity is being accessed via a WebHandler on PAS, not a standard REST service.  The WebHandler converts the dataset to JSON to return the data to the client.  Since I had to code my own REST functionality maybe I need to add code in the WebHandler to pass the errors through?

Do I need to handle the errors differently in my business entity code?  Or do I need to add code to the KUIB app to handle the errors on the front end?

TIA

Louis Winter

Posted by jts-law on 23-May-2017 08:08

Edsel,

I figured out the issue, and I apologize for the time you, Maura, and Shelley spent on this.  Because of an issue I was having early on with the popup editor, I added "grid.dataSource.read();" in a requestEnd event handler.  My custom error message was being returned but the extra call to read() was clearing it.  My error messages are now displaying correctly.

Thanks for all your help!

Louis

Posted by jts-law on 23-May-2017 08:14

Edsel,

I figured out the issue and the custom error messages are now being displayed correctly.

Due to an issue I was having early on with the grid not refreshing when I selected Cancel on the edit popup, I added "grid.dataSource.read();" in a "requestEnd" event handler on my datasource.  This extra read() was clearing the error message(s) that were being returned.

I apologize for the time that you, Maura, and Shelley spent on this issue.  It was a good learning experience though debugging this one.  Thanks for all your help!

Louis

Posted by jts-law on 23-May-2017 08:20

Edsel,

I figured out my issue and the custom error messages are now being displayed correctly.

Because of an issue I was having early on, I added "grid.dataSource.read()" to refresh the grid in a "requestEnd" event handler.  This was causing the error message(s) to be cleared.  I apologize for the time you, Maura, and Shelley spent on this.  Thanks for all your help!

Louis

All Replies

Posted by Shelley Chase on 19-May-2017 13:08

Hi Louis,

We were just working on this exact scenario and we have some found that the JSDO does not respond properly to the error and rejected flags. That will be fixed.

However, setting the error-string on the temp-table should be enough. I believe the issue is that you should not call reject-changes. This is mean to be used after the client has processed the results. Since this is a stateless environment, this is done by the JSDO after it gets the results with the flags, error, etc.

Removing reject-changes should help. Keep us posted.

Thanks

-Shelley

Posted by jts-law on 19-May-2017 14:40

Thanks for the info Shelley.  I removed the REJECT-CHANGES call and started a little deeper debugging.  The following is the basic code from my WebHandler:

DEF VAR oResponse   AS OpenEdge.Net.HTTP.IHttpResponse         NO-UNDO.

DEF VAR oWriter     AS OpenEdge.Web.WebResponseWriter          NO-UNDO.

DEF VAR iRC         AS INT                                     NO-UNDO.

iRC = INTEGER(StatusCodeEnum:OK).

oResponse = NEW OpenEdge.Web.WebResponse().

DATASET dsLookup:READ-JSON("JsonObject", poRequest:Entity, "EMPTY").

RUN Submit_Lookup IN hProc (INPUT-OUTPUT DATASET dsLookup BY-REFERENCE).

DATASET dsLookup:WRITE-JSON ("LONGCHAR", lcBody, TRUE).

oResponse:ContentType = "application/json".

oResponse:StatusCode = iRC .

oResponse:ContentLength = LENGTH(lcBody).

oWriter = NEW WebResponseWriter(oResponse).

oWriter:Open().

oWriter:Write(lcBody).

oWriter:Close().

How should the ERROR, REJECT, ERROR-STRING, etc. properties of the dataset get passed back to the client?  The response body back to the client has the data from the dataset as json which includes all of the data records/fields, but no additional attributes.

Louis

Posted by maura on 19-May-2017 15:00

We are currently working on sending the REJECTED info back to the client, but it sounds like you are setting the ERROR and ERROR-STRING attributes on the failed rows, so that will work, but your submit operation needs to be specified with before-image data to send this info along. So you should check that.

Can you send us the json that is being sent.

Also, just wondering if you are using the grid in the KUIB to make these changes?

Maura

Posted by jts-law on 19-May-2017 16:06

Hi Maura,

I'm using the popup on the grid to make the changes.

For testing, I have both a REST service as well as my WebHandler.  I did some more debugging sending my update (PUT) message through both services.  I found that the REST service was sending back the before-image and all other information including the error info.  The WebHandler service was not including the extra information.

I changed:

DATASET dsLookup:WRITE-JSON ("LONGCHAR", lcBody, TRUE).

to:

DATASET dsLookup:WRITE-JSON ("LONGCHAR", lcBody, TRUE, ?, FALSE, FALSE, TRUE).

Now I at least get the standard error popup with "Error while saving changes.".  The following is now being returned in the response.  How do I  get the "prods:error" value to display?

"prods:errors": {
"ttLookup": [
{
"prods:id": "ttLookup22784",
"prods:error": "Unable to update, record already exists for X."
}
]
}

Louis

Posted by egarcia on 22-May-2017 06:10

Hello Louis,

The error details can be obtained by calling the JSDO.getErrors() API.

The error handler code in Kendo UI Builder calls this API and displays the errors on a pop-up notification.

A key piece is that there should be a prods:clientId property set for the records in the after-image and the before-image.

The values of the properties would look like the following for a new record:

prods:clientId:"1495450966828-79"

prods:hasErrors:true

prods:id:"ttEmployee11337984"

prods:rowState:"created"

If the prods:clientId is missing, the JSDO would not be able to match the record (and the errors) to your the record in memory.

Do you get the prods:clientId property in the response?

Does it change based on whether it is a create, update or delete?

I hope this helps,

Edsel

Posted by jts-law on 22-May-2017 08:50

Hi Edsel,

The json below shows what was sent in the request and received back in the response.  I took these from the Chrome debugger.  As you can see, the response does have the properties you indicated.  Regarding the JSDO.getErrors(), do I need to have an error handler as well to display the error message I'm returning, or should the KUIB error handler be displaying the "prods:error" string in the response?  I am getting the "Error while saving changes." popup, but not the message from the response.

Request:
{"dsLookup": {
"prods:hasChanges": true,
"ttLookup": [
{
"prods:id": "1495458794520-399",
"prods:clientId": "1495458794520-399",
"prods:rowState": "modified",
"key_type": "Int",
"key_id": "Br",
"key_value": "90",
"description": "Test",
"group_description": "",
"group2_description": "",
"group3_description": ""
}
],
"prods:before": {
"ttLookup": [
{
"prods:id": "1495458794520-399",
"key_type": "Int",
"key_id": "Br",
"key_value": "9",
"description": "Test",
"group_description": "",
"group2_description": "",
"group3_description": "",
"_id": "1495458794520-399"
}
]
}
}}

Response:
{"dsLookup": {
"prods:hasChanges": true,
"ttLookup": [
{
"prods:id": "ttLookup33024",
"prods:rowState": "modified",
"prods:hasErrors": true,
"prods:clientId": "1495458794520-399",
"key_type": "Int",
"key_id": "Br",
"key_value": "90",
"description": "Test",
"group_description": "",
"group2_description": "",
"group3_description": ""
}
],
"prods:before": {
"ttLookup": [
{
"prods:id": "ttLookup33024",
"prods:rowState": "modified",
"prods:clientId": "1495458794520-399",
"key_type": "Int",
"key_id": "Br",
"key_value": "9",
"description": "Test",
"group_description": "",
"group2_description": "",
"group3_description": ""
}
]
},
"prods:errors": {
"ttLookup": [
{
"prods:id": "ttLookup33024",
"prods:error": "Unable to update, parameter already exists: Br, 90"
}
]
}
}}

Posted by egarcia on 22-May-2017 09:52

Hello Louis,

Thank you for sharing the output.

The request and response look fine.

> Regarding the JSDO.getErrors(), do I need to have an error handler as well to display the error message I'm returning,

> or should the KUIB error handler be displaying the "prods:error" string in the response?

> I am getting the "Error while saving changes." popup, but not the message from the response.

KUIB sets an errorHandler. It seems to be working because you are getting the popup.

My guess is that somehow getErrors() is not returning the error message. However, I would need a reproducible case to debug it.

Would it be possible for you to do some additional debugging and confirm what getErrors() returns?

You could try setting a breakpoint in errorHandler() in index.js and display table.getErrors().

Thank you and regards,

Edsel

Posted by jts-law on 22-May-2017 10:37

Edsel,

Within the errorHandler function the errors variable (table.getErrors()) is an empty array.  Below are the values from a few of the variables in the errorHandler function.

> errors

< []

> table.getErrorString()

< 0

> message

< "Error while saving changes."

> tableRef

< "ttLookup"

Louis

Posted by egarcia on 22-May-2017 15:16

Hello Louis,

It is interesting (and unexpected) that the value of the errors variable is an empty array.

We would need to debug the internals to see why the error text is not listed.

Could you log contact Technical Support with a reproducible case?

(I could create a reproducible case using the sample output but that would take me some time.)

Thank you and regards,

Edsel

Posted by jts-law on 23-May-2017 08:08

Edsel,

I figured out the issue, and I apologize for the time you, Maura, and Shelley spent on this.  Because of an issue I was having early on with the popup editor, I added "grid.dataSource.read();" in a requestEnd event handler.  My custom error message was being returned but the extra call to read() was clearing it.  My error messages are now displaying correctly.

Thanks for all your help!

Louis

Posted by jts-law on 23-May-2017 08:14

Edsel,

I figured out the issue and the custom error messages are now being displayed correctly.

Due to an issue I was having early on with the grid not refreshing when I selected Cancel on the edit popup, I added "grid.dataSource.read();" in a "requestEnd" event handler on my datasource.  This extra read() was clearing the error message(s) that were being returned.

I apologize for the time that you, Maura, and Shelley spent on this issue.  It was a good learning experience though debugging this one.  Thanks for all your help!

Louis

Posted by jts-law on 23-May-2017 08:20

Edsel,

I figured out my issue and the custom error messages are now being displayed correctly.

Because of an issue I was having early on, I added "grid.dataSource.read()" to refresh the grid in a "requestEnd" event handler.  This was causing the error message(s) to be cleared.  I apologize for the time you, Maura, and Shelley spent on this.  Thanks for all your help!

Louis

Posted by egarcia on 23-May-2017 09:45

You are welcome Louis!

We are glad to help.

As Shelley mentioned, we are working on a scenario like the one that you described.

> I have a very custom business entity object with many rules that allow/deny create/delete/update of records.

We would like to get some additional info on your scenario.

Would it be possible for you to provide some feedback on how you process the updates in your Business Entity?

Are you using the Submit operation? (The JSDO/Kendo UI DataSource automatically uses Submit if it is present in the Business Entity.)

Are you sending multiple creates, updates and deletes in a single request via the Submit operation?

If sending multiple updates, what transaction model are you using on the server?

A single transaction for all the updates or separate transactions for each update?

We appreciate your feedback.

Thank you and regards,

Edsel

Posted by jts-law on 23-May-2017 12:41

Edsel,

Disclaimer: I'm not 100% sure that I have everything setup "the right way", I've still been hacking at it to make it work.

Business entity/web handler setup:  I created a WebHandler class with methods to handle Get, Post, Delete, Patch, and Put.  Within the "Put", I have logic for my different invoke operations as well as the submit.  All WebHandler methods call the same methods as the REST wrapper class does.  One thing I'm not sure of is when I fill the dataset in the WebHandler class, which read-mode to use, I'm currently using "EMPTY".  Another "opportunity" with using a WebHandler is generating the schema json file.  To create the schema json file I generated a file using a REST service, copied the file, and changed the URI references.  This seems to be working so far.

Answers to questions:

>Are you using the Submit operation? (The JSDO/Kendo UI DataSource automatically uses Submit if it is present in the Business Entity.)

Yes, all operations are using the submit.  I wasn't sure why but you just answered that.

>Are you sending multiple creates, updates and deletes in a single request via the Submit operation?

In the current view, each operation is a single record.  I'm using the Add button above the grid for adds, and the Edit and Delete buttons on each row individually.  The selection type on the grid is set to "None".

>If sending multiple updates, what transaction model are you using on the server?

Not currently sending multiple updates.

>A single transaction for all the updates or separate transactions for each update?

If we allow multiple updates on future views, the plan will be to group all updates into a single transaction (all or none).

Also, I have run into another issue with my error messages.  Updates are working correctly but errors when adding new records doesn't work at all.  My business entity is generating an error when adding a new record, but no error message displayed in KUIB app.  As you can see below, the JSDO logic is expecting before-image information but the create is not generating any.

When debugging code -

  Exception thrown in "_mergeUpdateForSubmit" in "if (!recordId)" statement.

  Exception caught in "onReadyStateChangeGeneric".

Trace:

Error: JSDO: In '_mergeUpdateForSubmit()' function, before-image JSON data is missing prods:clientId

   at JSDO._mergeUpdateForSubmit (progress.jsdo.js:5900)

   at XMLHttpRequest.JSDO._saveChangesSuccess [as onSuccessFn] (progress.jsdo.js:6291)

   at XMLHttpRequest.JSDO.onReadyStateChangeGeneric (progress.jsdo.js:6726)

Additional info from "catch(e)" block of "onReadyStateChangeGeneric" function.  I can see my error message in _errorString.

>request.jsrecords[0].data

description: "Test 2"

group2_description: ""

group3_description: ""

group_description: ""

key_id: "Br"

key_type: "Int"

key_value: "9"

prods:clientId: "1495547858926-2729"

prods:hasErrors: true

prods:id: "ttLookup24832"

prods:rowState: "created"

_errorString: "Unable to create, parameter already exists: Br, 9"

>request.success

true

If I set request.success to false via the debugger, the "Error while saving changes." message is displayed, but still no custom message.  Let me know if you would like any additional information.

Louis

Posted by egarcia on 24-May-2017 08:58

Hello Louise,

Many thanks for the feedback. It is appreciated.

It helps to know that you plan on using a single transaction model (all or none).

Certainly, you have a very custom Business Entity by using a web handler configuration.

This should work fine. The key is to meet same protocol used with generated Business Entities (consistent request and response payloads for CRUD, Submit, and Invoke operations.)

Using EMPTY as the fill mode is fine. The fill() method in the JSDO expects that.

Generating the catalog by creating a REST (or WebHandler) service and copying the file is ok.

(Another alternative is to generate the catalog yourself and match the definition by using a catalog generated from PDSOE as an example. Here is a sample on a dynamic/generic service that uses this concept: community.progress.com/.../2677)

Regarding the error messages.

I am guessing that the issue is happening because a mismatch in the response received by the JSDO.

What does the payload look like?

Is prods:clientId present in the after table?

Is the error message returned as prods:error?

Here is an example for a test a sample app:

oemobiledemo.progress.com/.../ListView_FormWithCRUD

Response:

{

"dsEmployee": {

"prods:hasChanges": true,

"ttEmployee": [{

"prods:id": "ttEmployee428288",

"prods:rowState": "created",

"prods:hasErrors": true,

"prods:clientId": "1495632869659-63",

"EmpNum": 0,

"LastName": "Hall",

"FirstName": "Mark",

"Address": "",

"Address2": "",

"City": "",

"State": "",

"PostalCode": "",

"HomePhone": "",

"WorkPhone": "",

"DeptCode": "",

"Position": "",

"Birthdate": "2015-11-24",

"StartDate": "2015-11-24",

"VacationDaysLeft": 0,

"SickDaysLeft": 0

}],

"prods:before": {},

"prods:errors": {

"ttEmployee": [{

"prods:id": "ttEmployee428288",

"prods:error": "** Employee already exists with Last Name \"Hall\" First Name \"Mark\". (132)"

}]

}

}

}

I hope this helps,

Edsel

Posted by jts-law on 24-May-2017 16:40

Edsel,

BINGO!  Your example response helped a bunch.  I did have extra data in the response, my create errors are now displaying correctly.  Thanks again.

Louis

This thread is closed