Error handling~ Browser APIs ~

Error handling

There is one thing that developers forget very often - error handling. For me, there are two rules of proper error handling. The first one is to process the error in the right place. It doesn't make sense to add a try-catch block and log a message. The second rule is that the error should hold enough information to build context and react appropriately.

To illustrate the first rule, we will assume that we have a button that triggers a fetch request if clicked.

// somewhere in our services layer
async function getAllProducts() {
  try {
    const res = await fetch('/api/products');
    return res.json();
  } catch(error) {
    console.log('Ops! Something happen.');
  }
}
// in a React Component
<button onClick={async () => {
  const data = await getAllProducts();
  // render the data
}}>
  All products
</button>

It works, but it is not very useful. If the request fails and we catch the error, we can't do much with it in our service. On the other hand, if the try-catch block is inside the React component, we will render a message to the user.

// somewhere in our services layer
async function getAllProducts() {
  const res = await fetch('/api/products');
  return res.json();
}
// in a React Component
<button onClick={async () => {
  try {
    const data = await getAllProducts();
    // render the data
  } catch(error) {
    // render error message
  }
}}>
  All products
</button>

To fulfill the second rule, I like to create a custom type of errors. While handling the error, it is much better to use its type instead of relying on the message. For example:

class NoEmailError extends Error {
  constructor() {
    super("Missing email");
    this.name = "NoEmailError";
  }
}
function validatePayload(data) {
  if (!data.email) throw new NoEmailError();
  return true;
}
(function handler() {
  try {
    validatePayload({ name: "Jules" });
  } catch (err) {
    if (err instanceof NoEmailError) {
      console.log(`Error: ${err.message}`);
    }
  }
})();

The error handling guarantees that our application works even if something goes wrong. We should not underestimate this part of our development process. Again, we should deal with the error in the right place, and we should throw errors that bring context.