Developing with SAP Extension Suite

Explaining Error Handling

Objectives
After completing this lesson, you will be able to:

After completing this lesson, you will be able to:

  • Explain error handling

Error Handling - CAP Service SDK for Node.js

Usage Scenario

Having good error handling is key to ensuring the robustness, correctness, and performance of the given application. Building robust applications requires you to know how to throw and handle exceptions which occur during the runtime of the application. Thus, you will be introduced to the basic concepts of exception handling in Node.js as well as specific techniques for the CAP Service SDK for Node.js.

Error Handling and Error Types

Proper error handling is crucial for today's business applications. Before going into more detail, it is necessary to distinguish between two types of errors:

Programmer Errors
These occur as a result of programming errors (for example, foo cannot be read by undefined). They must be corrected.
Operational Errors
These occur during runtime (for example, when sending a request to a faulty remote system). They must be corrected.

Guidelines

"Let it crash" is a philosophy taken from the Erlang programming language (Joe Armstrong), which is also (partially) applicable to Node.js.

The key takeaways for programming errors are:

  • Fail loudly: Do not hide errors and continue silently. Ensure to log unexpected errors correctly. Don't catch errors you can't handle.
  • Don't develop in a defensive fashion. Focus on your business logic and only handle errors when you know they will occur. Use try/catch blocks only when necessary.

The key takeaways for programming errors are:

  • Fail loudly: Do not hide errors and continue silently. Ensure to log unexpected errors correctly. Don't catch errors you can't handle.
  • Don't develop in a defensive fashion. Focus on your business logic and only handle errors when you know they will occur. Use try/catch blocks only when necessary.

Never try to catch and handle unexpected errors, rejections of promises, and so on. If it is unexpected, you cannot handle it correctly. If you could, it would be expected (and should already be handled). Even if your apps should be stateless, you can never be 100% sure that a shared resource was not affected by the unexpected error. Therefore, you should never allow an app to continue running after such an event, especially for multi-tenant apps where there is a risk of information disclosure.

Following these guidelines will make your code shorter, clearer and simpler.

Never Hide the Causes of Errors

When an error occurs, it should be possible to know the root cause. The CAP SDK for Node.js also throws exceptions, for example when a CRUD operation violates the foreign key constraints. In this case, the framework throws the exception UNIQUE_CONSTRAINT_VIOLATION. The problem in this case is that the end user will only see a more or less cryptic error message:

It is therefore useful to provide a meaningful error message.

For this purpose, you can register an error handler in your service implementation, see an example in the editor:

Example code:

Code snippet

// Imports
constcds=require("@sap/cds");

/**
   * The service implementation with all service handlers
   */
module.exports=cds.service.impl(asyncfunction(){
  /**
   * Custom error handler
   *
   * throw a new error with: throw new Error('something bad happened');
   *
   **/
  this.on("error",(err,req)=>{
    switch(err.message){
      case"UNIQUE_CONSTRAINT_VIOLATION":
        err.message="The entry already exists.";
        break;

      default:
        err.message=
          "An error occured. Please retry. Technical error message: "+
          err.message;
      break;
    }
  });
});
Copy code

This handler now steps in whenever this exception gets triggered and overrides it with an alternative error message:

Raising and Catching Exceptions

You will certainly add your implementations to your services. It is very likely, that you want to interrupt some operations before something crashes. In this case, you can throw a Node.js exception. Our recommendation is to look at the Node.js documentation for error handling.

Request Response

You can also use the req.error() method to collect messages or errors and return them to the caller in the request-response. Read more here .

Code snippet

this.on("submitOrder",async(req)=>{
  const{ book, amount }=req.data;
  let{ stock }=awaitdb.read(Books,book,(b)=>b.stock);
  if(stock >= amount){
    awaitdb.update(Books,book).with({stock: (stock-=amount)});
    awaitthis.emit("OrderedBook",{ book, amount,buyer: req.user.id});
    returnreq.reply({ stock });// <-- Normal reply
  }else{
    // Reply with error code 409 and a custom error message
    returnreq.error(409,`${amount} exceeds stock for book #${book}`);
  }
});
Copy code

Summary

The core error handling concepts in the CAP SDK for Node.js are now familiar to you. We strongly recommend incorporating these concepts to ensure the overall robustness of your CAP application.

Save progress to your learning plan by logging in or creating an account