When you create an Application, you try to follow as much as possible the Business requirements and the recommendations related to Best Practices and Performance. However, even if your logic is nearly perfect, users, browsers, networks, and servers are experts at turning your application upside down. When an interaction with the application doesn’t have a predesigned behavior or jumps outside the scope of your business plan, an Exception can be launched.
The good news is, Applications implemented with the OutSystems Service Studio already have a mechanism to handle Exceptions. Thus, this article will showcase how OutSystems deals with Exceptions.
Note: the examples in this article were developed in an OutSystems Web Reactive application, using the Service Studio version 11.8.12, based on SQL Server. If you would like to know more about the OutSystems Platform and Service Studio developer tool, please follow the links:
Before we start exploring how to handle the Exceptions, we will explain what an Exception is and what kind of exceptions you can expect inside the OutSystems Platform.
“An exception is an exceptional circumstance that prevents your application flow from running normally. (...) You should raise exceptions only for exceptional circumstances and not to control the logic of your application. When an exception is raised, the execution of the application flow is interrupted.” - OutSystems - Handle Exceptions
Types of OutSystems Exceptions
Database Exceptions are raised by OutSystems when there is an error related to the database management system, like a User trying to update a record that no longer exists.
It will be triggered whenever there is a communication problem between client and server (e.g., no internet connection). Weak connections may also lead to Communication Exceptions whenever the server fails to reply within the specified timeout value.
Security Exceptions can arise whenever you have authentication or other security mechanisms in the application module. For instance, your user authentication fails, or the specific user doesn’t have the minimum role necessary to access a screen or execute an action.
Abort Activity Change Exception
Using this exception in a Process Activity callback action will prevent the activity from advancing to the next state. If you want to know more about the Process Activities topic, click on the link.
All Exceptions is used as a general exception. Meaning that the Exception Handler of this exception will arise to deal with any exception if there is no more specific handler.
Besides the automatic exceptions, OutSystems allows creating User Exceptions and raising them in the app logic. Thus, if your user or logic flow doesn’t match the expected behavior, it will raise an exception. Simple things, like an invalid credit card number to pay a bill, cannot be a reason to freeze the app. So instead of blocking the user interaction, you can provide a different path that gives feedback to the user by displaying messages on the screen.
How to create a User Exception?
In OutSystems Service Studio, you have two ways to do it. You can go to the Logic layer, and inside the respective folder Exceptions, right-click Add User Exception, or you can trigger an Exception inside your actions flows. Instead of choosing an existing one, you can select the option New User Exception. Then, on the Logic layer, you can change its name.
To learn more about raising exceptions, please check the OutSystems Documentation here.
Where Can You Find the Exceptions?
Once you create an application in OutSystems Service Studio, open the Logic layer, and inside the respective folder Exceptions, you will find the existing ones.
Now that we know what kind of exceptions we have and how to trigger them, let's jump to the main subject of this article. First, we will talk about the built-in action On Exception, then how you can define different handlers, and finally, debate some scenarios to clarify how each handler will be executed if you have more than one in an action flow.
The OnException is a predefined action that handles any exception your application throws. This action brings your application-specific handlers to deal with exceptions like Communication or Security. It also provides a generic handler–All Exceptions– that returns an error message to the user based on the Exception error.
Where Can You Find the OnException?
Open the Interface layer, as displayed on the image, and you will find the OnException action inside the Common Flow.
How Does the OnException Action Work?
The OnException action includes, by default, a Security, Communication, and All Exceptions handler flows.
The Security handler will be executed if a Security Exception is raised – like a User that doesn’t have valid credentials when trying to access a screen. But if the communication with the server fails, a Communication Exception will arise, and the respective handler will be executed. In other scenarios, the All Exceptions Handler can also run.
The image below shows these predefined handlers inside the OnException action.
However, if you need different behavior, you can adjust these flows or add more specific handlers.
Adding a New Handler
An Exception handler catches an exception or set of exceptions. Besides the default Exceptions and Handlers, not only can you create your own User Exceptions, but you can also design different Handlers with the respective logical behavior.
To add a handler to an action, drag and drop the Exception Handler tool inside the action and select what kind of Exception the handler must solve.
So, What Handler Will Be Executed?
The first thing we need to remember is that only one handler flow will be executed, and always the most specific one. The Exceptions' handler mechanism follows a hierarchy determining which Handler must be executed. If you search for "handler exceptions" on the OutSystems documentation, you will find the image below representing the Exceptions' hierarchy nodes. Essentially, when you raise an exception, the platform will check if a handler for that specific exception exists. Otherwise, it will bubble up on the hierarchy to the Handler immediately above, and so on.
For example, the Exception Not <Role 1>: a user must be a Chief Financial Officer (CFO) to approve an invoice but doesn’t have that permission role yet. Assuming the exception name is NotCFO, when an Exception of this type arises, the code will execute the respective handler if it exists.
But if your application doesn’t have a handler for the NotCFO Exception, the Exception Handler Mechanism will check what will be the next handler in the hierarchy. In this case, the handler directly above will be the Not Registered.
If the application doesn’t have a handler for the Not Registered Exception, then a Security Exception Handler will be executed. And if none of these handlers exist? Then, the All Exceptions Handler will be the one to be executed.
Now that we know that only one handler will be executed, and it will be the most specific one in the hierarchy, there is another situation to consider. If there isn't a handler flow on the same scope where the exception arose, the Exception Handler Mechanism will check if another handler flow can be used outside the current scope. Summarily, the mechanism will follow the path beginning on the current scope to determine if another handler can be used, or if not, until it reaches the OnException. The following scenarios will help us understand the Handler Mechanism behavior to determine what handler it will execute.
Scenario 1 – Handler Inside the Same Scope
In the previous example, a Server Action checks if the current user has the CFO role. If the user has that role, it will return a boolean (Has Role) with the value True. If not, the NotCFO Exception will be thrown.
We have three different handlers inside this Server Action: NotCFO, NotRegistered, and AllExceptions.
If you analyze the code, you will see that if a User without the CFO role tries to execute the current action, a NotCFO Exception will arise.
Looking at the handlers, it is easy to find the one being executed: inside the same scope the exception is thrown there is the NotCFO Handler. Thus, all other handlers in this scenario will be ignored.
Scenario 2 – Handlers Inside the Same Scope, But Not the Specific One
Inside the Server Action, there is no Not CFO Handler, so the handler mechanism will bubble up to the next handler and check if that one exists.
Looking again at the hierarchy, if the Not <Role> doesn’t exist, the immediately above handler will be Not Registered. Since Not Registered is one of the available handlers in the current scope, that will be one executed.
Scenario 3 – Only the All Exceptions Handler Inside the Same Scope
Inside the Server Action, there is only the All Exceptions Handler.
Because the handler mechanism cannot find a NotCFO Handler, a NotRegistered Handler, or a Security Exception Handler, the last option available on the hierarchy will be the All Exceptions Handler.
Scenario 4 – Handler Outside the Scope
The CheckCFO Server Action throws the Not CFO Exception but doesn’t have a handler to handle it.
In this scenario, the handler mechanism will bounce to the action calling the CheckCFO Server Action to check if there is any handler to handle the exception.
Inside the Client Action (left flow in the image), responsible for calling the CheckCFO Server Action, exists a NotRegistered handler. Considering this is the most specific one in the current execution to handle with the Not CFO Exception, the handler mechanism will choose it to solve the exception.
Scenario 5 – Lacking Handlers
In this scenario, if an Exception is thrown and the current Action or the Action responsible for calling it don't have any Exception Handler, the handler mechanism will jump to the OnException Action.
Finally, the most specific handler in the OnException Action will be executed, as in the previous scenarios.
Scenario 6 – Always the Most Specific Handler?
Up until now, we saw that the most specific handler will always be the one to be executed. And in the case the handlers are missing, the mechanism bubbles up not only through the exception types but also the actions until, in the last instance, it reaches the OnException Action.
However, what if the most ‘generic’ handler–e.g., AllExceptions–is in the scope, and the specific handler–like NotRegistered–is in the parent action of that scope? What handler do you think will be executed?
Well, it is simple: if there is a handler that can solve the exception inside your current flow, the mechanism will select that one. So in the present scenario, the AllExceptions Handler is a valid option to solve any exception. Further, considering it is the handler available in the same scope raising the exception, it will handle it.
Now, you can easily control an application's behavior when a User interaction is not expected. Besides the predefined exceptions and handlers, you can create your Business Exceptions and define alternative paths.
Furthermore, you can explore the Exceptions hierarchy and choose the proper handlers to provide your customers with better and friendlier applications.
This article only covers the basics of OutSystems Exceptions and Handler concepts. To learn more about Exceptions and Handlers in OutSystems, resort to the comprehensive documentation, courses, and the OutSystems Community. Plus, consider improving your skills by understanding how you can troubleshoot the Exceptions through the Debugging mechanisms and the Service Center platform.
Are You a Beginner in OutSystems?
Check out the courses on our website. We recommend the Turn Up Boot Camp if you're considering a career shift into tech or the OutSystems world. Alternatively, you could register for the Reactive Developer course if you are just interested in achieving the basic skills to create your own Reactive apps. Both include the certification for the exam Associate Reactive Web Development upon completion.