• 10 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 4/2/20

Be ready when things go wrong

How many times have you been using a web app (or any other computer program for that matter) when things just…stopped working?  It is very unlikely that we will ever be able to stop errors from occurring in our apps. What we can do, though, is try and set things up so that errors are reported clearly and do not simply cause our app to crash.  For this purpose, we need error handling.

Error handling

In everything we code, we should do our best to make our code as robust and reliable as possible. Basic JavaScript error handling is often achieved with  try...catch...finally  blocks, and although this can be good enough in some cases, there are many strategies for code reliability.  

For example, if you have a function that requires three arguments, will you use a try/catch block to try and manipulate them? Or would it be better to test for the arguments before doing anything and sending back a meaningful error message? Or should you use default values? There is no single "right answer" to these questions, but what would be wrong is to ignore the problem completely.

Let's go back over the code from the previous chapter and see how we can make it more robust.

Practice!

Head to CodePen Exercise P3CH4a and follow the instructions below.

Let's go down through our code and see where improvements can be made without sacrificing too much performance.

The first thing I notice is our makeRequest() function. We allow for three arguments (which we need to do), but we will only be passing the third data argument if we want to make a POST request. In fact, the data argument is mandatory for a POST request.

Now, we could easily make a check in the first line of our function which would return 0 if someone tried to make a POST request without a data object. However, this would wreck our entire async function. Perhaps we should find a better solution.

Perhaps we should place the check inside our Promise and reject it with a custom error object if the check fails.

  1. Just inside the beginning of our Promise, create a check where, if the passed verb is POST but no data object is passed, the Promise rejects with a meaningful error message.

    Hint: make the error object of type { error: string } to conform to the error types returned by the API.

  2. Our makeRequest() function also fails to check if the verb it receives is valid — remember, we only want GET or POST requests. Let's add a check for that too. Create a check which will reject the Promise with a meaningful error if the verb argument is anything other than 'GET' or 'POST'. Right! Our makeRequest() function is now much more robust.

  3. Let's move on to createPost(). In previous chapters, you saw that we can use try and catch to handle async/await errors. In fact, we haven't handled a single error in createPost() yet! Let's solve that now. In createPost(), we make three parallel calls, followed by one single call which relies on the success of the previous three. Therefore, we

    need something along the lines of:

    try {    
        // three calls    
        try {        
            // final call    
        }    
        catch (error) {        
            // handle final call error    
        }
    catch (error) {    
        // handle three calls errors
    }

    Remembering that the error that is thrown by makeRequest() is of type { error: string }, set up try...catch blocks that follow the above structure and handle errors correctly. 

Once you've given it a go, watch me code a solution and see how your approach compares:

Just these few seemingly simple steps can make a real difference between buggy, hard-to-maintain code and a robust, maintainable, reliable app.  Writing code with error handling in mind will also make you write better code, as you will constantly be wondering about what could go wrong and preemptively avoiding unnecessary errors.

Let's recap!

In this chapter, we had a look at how to approach error handling. In particular, we saw:

  • how to use simple checks to prevent functions from failing,

  • how to use try...catch blocks with nested async/await to handle errors gracefully.

Example of certificate of achievement
Example of certificate of achievement