Chapter 5 - Error Handling¶
This tutorial is based on the error_handling.js example, which can be found in the TRAC GitHub Repository under examples/apps/javascript.
Error handling basics¶
The TRAC web API bindings support both futures and callback-style API calls. The same error handling capabilities are available in both styles.
As a basic example, we can send an invalid request to the server and it will respond with a validation error. Here is what that looks like using futures:
64 // Handle an error in the API call using futures
65 return metaApi.createObject(badRequest)
66 .then(_ => {}) // handle response
67 .catch(error => {
68 // handle error
69 console.log("There was a problem creating the object: " + error.message);
70 console.log("gRPC status code: " + error.code);
71 });
The error.message property contains a short human-readable description of the error. You can also access the gRPC status code using the error.code property. Both of these properties are available even if communication with the server fails, for example in the case of network errors.
Note
A list of gRPC status codes is available in public documentation for gRPC: https://grpc.io/docs/guides/status-codes/
Exactly the same error handling capability is available using callbacks:
80 // Handle the same error using callback-style API calls
81 metaApi.createObject(badRequest, (error, _) => {
82 if (error != null) {
83 // handle error
84 console.log("There was a problem creating the object: " + error.message);
85 console.log("gRPC status code: " + error.code);
86 } else {
87 // handle response
88 }
89 });
TRAC Error Details¶
Sometimes it is helpful to get more detailed information about an error. For example, in the case of validation failures, there can sometimes be multiple issues and we want to know exactly what those issues are and where in the input they occurred. Fortunately, TRAC has a means to provide this information.
98 // Handle an error in the API call using futures
99 return metaApi.createObject(badRequest)
100 .then(_ => {}) // handle response
101 .catch(error => {
102 // Get structured error details
103 const details = tracdap.utils.getErrorDetails(error);
104 console.log("There was a problem creating the object: " + details.message);
105 console.log("gRPC status code: " + details.code);
Use getErrorDetails()
to get a TracErrorDetails
object. The details.message and details.code properties are the same as for basic
error handling and are always available. However, if the server provided more detailed
information, this can be accessed by looking at the individual error items:
106 // Show more detailed information
107 details.items.forEach(item => {
108 console.log(item.fieldPath + ": " + item.detail);
109 });
For each item, item.detail is a human readable description of the error. For errors related to the request (mostly validation errors), item.fieldPath is the field path for the input field that caused the problem.
Errors in streaming calls¶
See also
See Chapter 4 - Streaming for more details on the streaming data API.
Errors in upload streams
With upload streams, the client sends a series of messages to the server and receives a single message or error in response. The error handler can be attached when you send the first message to the stream:
stream.createDataset(request0)
.then(_ => {...}) // Handle upload success
.catch(error => {
// Handle upload error
const details = tracdap.utils.getErrorDetails(error);
...
});
// Now send the rest of the messages to the stream
stream.createDataset(msg1);
stream.createDataset(msg2);
...
Similarly if you are using callback style, a callback is only needed for the first message of the stream.
Errors in download streams
For download streams, the client sends a single request to the server and receives a stream of messages in response. An error can occur at any point in the stream and has to be handled using a stream event handler.
Because errors are processed using stream events, the futures / callback handlers should be explicitly set to no-op functions to avoid unhandled or duplicate events.
// Handle the download stream
stream.on("data", msg => {...});
stream.on("end", () => {...});
stream.on("error", error => {
// Handle download error
const details = tracdap.utils.getErrorDetails(error);
...
});
// Disable future / callback processing, because we are using stream events
stream.readDataset(request)
.then(_ => {})
.catch(_ => {});
Using promises for streaming operations
In Chapter 4 - Streaming, the streaming operations are wrapped up into promises and errors are
passed directly to the promise resolve() method. Once the operation is wrapped up into a promise,
errors can be processed using a regular .catch()
.
For example, the streaming download API readDataset()
is
wrapped up into a promise by loadStreamingData()
and handled as shown in this example, hiding the
details of the stream event processing:
146 return loadStreamingData(dataId)
147 .then(_ => {}) // Handle success
148 .catch(error => {
149 const details = tracdap.utils.getErrorDetails(error);
150 console.log("Download failed: " + details.message);
151 details.items.forEach(item => console.log(item.detail));
152 });