I like working with AJAX and Application Processes in APEX, but I've had times where I find it difficult to handle errors/exceptions in a consistent fashion.

HTTP provides a convenient way to determine if something went wrong with a request to the server. The HTTP status code. API developers will use the HTTP status code to let the front end know whether a request has been successful or not. For example...

200 - OK
500 - Internal Server Error

The HTTP utilities of various JavaScript libraries and frameworks work based on the assumption that the back end will return the appropriate HTTP status code for the response.

apex.server.process(
  'GET_STUFF'
).done(function() {
  alert('Success'); // Triggered when HTTP status code = 200
}).fail(function() {
  alert('Failure'); // Triggered when HTTP status code = 500
});

Unfortunately, in an APEX application process, throwing an exception will still result in a 200, meaning that in the above snippet, the .done handler will be called even though there was an application failure.

Having reached out on the apex.world Slack group, Roel Hartman told me that he builds up a nicely structured JSON string to send back with his responses. I liked this idea, so I've had a go at implementing this in an application process.

Normally, I'd return a statusCode of 200, along with any data required to satisfy the request.

htp.prn('{"statusCode" : "200", "stuff" : ' || v_data || '}');

But, whenever I want to handle an exception, I can specify a different statusCode and replace data with errorMsg.

EXCEPTION WHEN my_exception THEN
   htp.prn('{"statusCode" : "500", "errorMsg" : ' || SQLERRM || '}'); 
END;

Now in my call to the process I can do something like...

apex.server.process(
  'GET_STUFF'
).done(function(data) {
     if (data.statusCode == 200) {
        doSomethingWithStuff(data.stuff);
     } else {
        handleServerError(data.errorMsg);
     }
});

Bear in mind I don't have to use these particular statusCode values. I can use anything, since I'm just setting my own arbitrary application status code, not setting the HTTP status code header.

Actually, it's probably better to drop the statusCode all together and move the logic around, since we can simply check for the existence of errorMsg.

apex.server.process(
  'GET_STUFF',       
).done(function(data) {
   if ("errorMsg" in data) {
      handleServerError(data.errorMsg);
   } else {
      doSomethingWithStuff(data.stuff);          
   }
});

Now, it wouldn't take much more to wrap this up into a more generic wrapper function that we could reuse whenever we want to respond to errors from the server with a standard error handler.