Web API Error Management – Part 2
In Part 1 of this article, we reviewed the types of error conditions that can occur in web APIs and the basic methods available for handing these situations. As previously noted, developers are not confined to handling errors in only one manner. In this article we’ll look at the advantages of each error handler and propose a few standard configurations for common situations. Developers can then use and adapt a configuration that best serves their needs.
What’s Up Doc?
Much of the information provided below summarizes what is already available in various documents from both Revelation Software and SRP. Having access to official sources is helpful, especially when our examples might not fit your situation. Therefore, we recommend making sure you have these materials on hand:
- OECGI3.EXE Installation and Configuration Quick Start Guide (Note, this information applies to OECGI4.exe as well.)
- OpenInsight OEngineServer Configuration
- SRP HTTP Framework Wiki
Error Management in a Development Environment
Many systems maintain a developer environment (and perhaps a test environment as well). In a development environment it is important to get as much feedback as possible with regard to runtime and status errors, even if this requires the web service to abort. The easiest way to accomplish this is to enable the OpenInsight Debugger. This allows the developer to catch runtime errors and debug statements using the same techniques as with OpenInsight desktop applications. There are just a few steps required for this to work:
- The Engine Server must be ran in console mode rather than as a Windows Service. In the Windows Services utility (or the Services tab on the Task Manager), find OEngineServer and make sure it is stopped. Then open a command prompt and change the path to the folder where OpenInsight is installed. Assuming the 32-bit Java binary is already defined in the Path environment variable, the following command can be entered to start the Engine Server in console mode:
java -jar oesocketserver.jar -d 3
- The StartupFlags value in the Registry must be set to 1. Sometimes this value is set to 65. Both behave the same with regard to starting up OpenEngine, but 1 allows the engine to be visible, which is required for the OpenInsight Debugger to also be visible.
- Debugger Settings must be set to Enable. If you don’t mind this being set permanently, this can be configured through the Database Manager > Environment Settings dialog. If you want to limit this setting for web services then just configure this through the HTTP Framework Setup dialog.
- An Aborted service handler (e.g., INET_ABORTED or HTTP_Aborted_Service) should be properly configured. It will still get called even if the OpenInsight Debugger was invoked from a runtime error. This occurs after the debugger is closed.
Error Management in a Production Environment
Ideally, production environments should never encounter an error condition. But we live in the real world where unforeseen events can arise so our APIs need to be able to respond appropriately. So let’s review some options that would best suit a web application running in a production environment.
- In this scenario, the Engine Server should normally be configured to run as a service. The primary reason for this is so that the Engine Server can automatically restart whenever the server itself is restarted. Also, this will help prevent the OpenInsight Debugger from being invoked if a runtime error is encountered. Refer to page 5 of the OEngineServer Configuration document for instructions on installing the Engine Server as a service.
- If the Debugger Settings is set to Enable, the StartupFlags value in the Registry should be set to 65. When the Engine Server is running as a service it prevents the OpenInsight Debugger from becoming visible. However, a StartupFlags value of 1 allows OpenEngine to remain running in a debug state. The HTTP Request fails to complete and the session is forced to time out. Additionally, a license is kept in use for each HTTP Request that encounters a runtime error, which might eventually cause a “too many users” condition. If the Debugger Settings is not set to Enable (see next bullet point), then this value can be either 1 or 65.
- Debugger Settings should be set to Disable. Optionally this could be set to Enable, but the StartupFlags should be set to 65 so runtime errors do not keep OpenEngine sessions running indefinitely.
- An Aborted service handler (e.g., INET_ABORTED or HTTP_Aborted_Service) should be properly configured. This will allow the API to format the error in an acceptable HTTP Response. If the Aborted service handler is not configured then a generic response will be returned.
What About the Debugger Intercept?
Neither of the two configurations provided above mention the Intercept Debugger Setting. The primary reason for this is because there is no guarantee that the developer’s code will retain control. As mentioned in our previous article, some runtime errors create a scenario where the Engine Server cannot recover. The session times out and the web server returns its own 500 status error. In cases where the runtime error is not catastrophic, the original API code will continue to execute. However, this means the results might not be reliable. Thus, in both situations, using a Debugger Intercept can result in an unfavorable HTTP Response.
One advantage provided by the Debugger Intercept is more information relating to the runtime error. While an Aborted service handler will be provided basic runtime error information (e.g., error text, procedure name, and line number), the Debugger Intercept can also provide the call stack, the line number for each procedure in the call stack, and the depth of the current stored procedure. This information can be helpful in diagnosing the origins of an error, but it comes at a cost of unpredictable HTTP Responses.
A Few Words about Status Errors
We have already mentioned that errors resulting from a Set_Status(1) will result in the Engine Server populating the ProcErr argument. Like runtime errors, this information will be passed into the configured Aborted service handler. A status error can be raised by a system stored procedure (SSP), or the developer can raise it directly within a web service.
The Aborted service handler allows the developer to maintain control but it might not provide the best experience. Consider a situation where an RList() call fails. By default, this will create a status error and the Aborted service handler will be provided the error text. The Aborted service handler must then package the error text in a generic HTTP Response or it must be programmed to deal with specific status errors for specific requests. Neither of these two options is ideal. Therefore, developers may want to consider defensive programming within the immediate web service logic and handle the error directly. Just check Get_Status() after an SSP call, clear the status using Set_Status(0), and then package the HTTP Response using the most appropriate status code and response body within the context of the current web service code.
An additional tool in the SRP HTTP Framework box is a utility service called Error_Services. This module includes a handful of services that can be useful for web applications. Errors can be raised via the Set or Add service. These errors are kept until the Clear service is called, which is normally only done when the HTTP Response has already been created and is ready to be returned back to the Engine Server. This means that any stored procedure called during the life-cycle of the web service can check for error conditions and respond accordingly. The NoError and HasError service are convenient when conditional logic is required:
If Error_Services('NoError') then // There is no error. Continue processing. end else // There is an error condition that needs to be handled. end If Error_Services('HasError') then // There is an error condition that needs to be handled. end else // There is no error. Continue processing. end
Additionally, the GetMessages (or simply GetMessage) service can be called to retrieve the current errors in the stack. This will return all errors generated during the current web service session, thus providing the developer an opportunity to make an informed decision on how the HTTP Response should be formatted.
A Final Word regarding HTTP Status Codes
The prevailing theme of this article has been about developer control. This may have limited importance in your application. However, the SRP HTTP Framework was designed with consumable web services in mind. This refers to web services that are designed for a broader audience rather than your own internal web application. When developing a published web service (perhaps as a commercial product), it should conform to standard HTTP guidelines. This is also an important constraint of REST (i.e., Uniform Interface). The practical benefits of this are ease of use and predictability. Conformity to a known standard reduces the learning curve and legitimizes your web service. Therefore, take the time to become familiar with the common HTTP status codes. The rule of thumb is to use a more specific code whenever possible (e.g., a 405 Method Not Allowed status is better than a 400 Bad Request status if applicable). A little investment in this area will serve you well in the long run.