Rework validations and error handling - Mendix Forum

Rework validations and error handling

8

Problem statements:

Validation mechanisms are inconsistent and difficult to implement. Do you validate in nanoflows? Or in microflows through decision points and rules? Perhaps it should be done on entities through before commit handlers or should you set attribute level validations? Do you validate everything at once or do you go field by field and do you want to give back this feedback to a form? What if there is no UI element visible for that attribute? What if the error that caused the validation to fail is a combination of factors? Where do you show your validation message? What if there is no UI at all? And instead this validation occurs when the commit happens as a result of an API call? Or even more fancy, straight from javascript in the browser console? 

 

The next problem is that everyone of us has ran into a situation in our code where we need to throw a hard error (Can't be done without CommunityCommons), immediately you're challenged by, should you include stack trace or not? What's the difference? What would actually be logged? How is this perceived by the user? Should I still log this separately using $latestError/message? etc.  

 

In the end as developers we're just challenged by the Mendix IDE on how we're supposed to handle faulty situations gracefully. I strongly believe this is currently barely possible. And because of this reason I believe this should be reworked, made more accesible, consistent, and re-usable.

 

Proposed solutions:

 

Make a transaction HTTP statuscode variable available to be set by the platform or by the user manually.

Mendix code runs in a transaction. When the transaction fails there should be a transaction code variable that acts like a HTTP statuscode, which by default I should be 200, and can be changed based on access rights to 403, or 400 if a validation error occurs, or 500 if an error is thrown. This variable should be available within each microflow/nanoflow and can be set by the user, or by the platform.

 

Add a new concept called middleware

- Introduce a new concept called "middleware" on entities, which sort of works like event handlers (these could also be reworked), however we want the possibility to add other associated entities as parameters into the microflows that are triggered as middleware. The idea is to create a central place for handling data sanatization, validation, and enrichment or logging or event publishing. By adding this as a new concept, no old code should break. However slowly developers could transition to this middleware usage.

- Allow for setting a sequence/sort order on the middleware through indexes. 0 first 1 second etc.

- When commiting or changing an object or importing it through an import mapping with commit, it's possible to select which middleware should be executed at that time. An extention of "commit with actions" but with more granular control over which actions should be done, if additional parameters are required as part of the middleware either the relevant association or available data in that transaction can be selected as the input for that additional parameter. 

 

Make manual validation messages and database entity validations generate the same JSON structured error messages and catch these in the Mendix frontend or as API responses to faulty import mappings.

- Always collect validation messages until a return point or error point has been reached within a nanoflow or microflow.

Transform validation errors in a structured JSON regardless of whether they were manually created as part of the nanoflow or microflow actions. Or if they were part of the entity attribute validations. If a validation error occurs throw an error with this JSON structure only, without additional stacktrace details. And make sure the statuscode is turned into a 400 Bad Request. By doing so it has become much easier to validate consistently across available front-end or API's or cross mendix applications with datahub. As this could be directly transformed into a HttpResponse entity.

 

StatusCode would be a reference to standard HTTP response codes

ReasonPhrase would be the related textual description for that HTTP response code

Errors contains an array of the captured errors.

 

Each error would then contain:

Code: a textual code description for the error that has occurred, can be set manually in microflow validation actions or could be generated based on entity attribute validations. Could immediately be documented.

Message: A short title or description of what the error entails

Details: A more elaborate description of the error and what steps should be taken by the end user.

Url: A custom URL, preferrably with an {%appURL%} token that has no / at the end, could also point to stored "stacktrace messages" in the case of a thrown error. Which is temporarily viewable in session by the user and stored for mendix developers as part of the logs.

Field: Refers to the entity name and then either the GUID between square brackets or another unique attribute, preferably autodetects if a UniqueID or _Id attribute exists on the entity or if defined by the API mapping on which this validation message is thrown, uses the field marked as "Key". Followed by the attribute name or association name or even associaton name plus the associated entity name + guid/unique ID and attribute name.

Target: Gives the ability to target a specific HTML element if the up above field cannot be identified through entity + unique identifier as part of the UI.

OriginalValue: Captures the input value that was coming in when this validation message broke.

 

{  
   "StatusCode": 400,
   "ReasonPhrase": "Bad Request",
   "Errors": [
      {
         "Code":"email-is-invalid",
         "Message":"Email is not valid.",
         "Details": "You're required to provide a valid e-mail address to continue.",
         "Url": "https://yourappurl.com/p/docs/errors#email-validation-errors",
         "Field": "EntityName[GUID].AttributeName",
         "Target": "Webbrowser XPath to element or CSS class",
         "OriginalValue": "my-invalid-emailaddress@"
      },
      {
         "Code":"account-not-part-of-user-group",
         "Message":"The account should be part of a user group.",
         "Details": "Please make sure to assign this new account to an user group.",
         "Url": "https://yourappurl.com/p/docs/how-tos#creating-new-accounts",
         "Target": "Webbrowser XPath to element or CSS class",
         "Field":"EntityName[GUID].EntityName_AssociationToEntityName",
         "OriginalValue": null
      }
   ]
}

 

Showing the validation message in the UI

Because we now have a lot more information, I would expect there to be more beautiful and detailed error messages. Where the message is initially displayed as the error. But depending on whether there are details, a question mark icon is added right next to the error message which on hover tooltips you the details. And perhaps a link icon to take you to the provided URL for additional information. Obviously all this should also be made accessible for users using the tab key to navigate through page elements and should have correct aria behavior/screenreader behavior.

 

Re-use the same JSON structure for showing error pop-ups in the case of a thrown error.

As described up above, this same structure could be used for throwing errors back to the user.

Where we can set a code, message, details, the error target becomes the HTML body or window, and mendix auto generates an URL for the stacktrace details, which when clicked by the user takes them to the submit feedback page and auto includes the link to the stacktrace for developers to look at. And I believe that throwing an error should become standard for the Mendix code actions and not rely on a JAVA action in CommunityCommons.

 

This could then also be captured in a much nicer UI pop-up giving the user more grip on an error than the default "contact an administrator" situations that now occurs.

asked
1 answers

I like the json idea ;-) The validation part I have written about extensively; all that can be done and pretty re-usably, if you create a proper validation module. I know mx pm's have discussed the option of coming up with flows that both work on server/client, so that a sub val flow could be called in either a nano or microflow. Looking forward to when that arrives. Best would be a "Validate" action, that calls on a validation that is maintained at entity level, like you describe, where you can select certain attributes for validation in each instance. E.g. in page A, I only want attributes X Y Z, and in B, E F G. 

 

Translating validation messages is also a thing I am missing here; would be nice to include that in your idea. 

Created