CPNT 262 Day 21 - Mongoose with async/await and try/catch

Housekeeping

  • Assignment 3 marks published.

Trophy of the day

  • Assignment 3 refactored to use async/await and try/catch

1. Promises with async/await

Materials

Key Takeaways

  • async/await is a newer and alternative syntax for Promises, which function the same way as with .then() and .catch().

  • Only 95% of browsers (as of Nov 2021) understand async/await but all updated Node servers understand it. You don't see .then() and .catch() very often on the server side.

  • In order to use the await keyword, you need to wrap your code inside a function defined with the async keyword.

    const hello = async function() { 
    // `await` can now be used inside this function
    return "Hello"
    };
  • await is used to "pause" your code when invoking a function that returns a promise, like fetch() or model.find() and .then().

    const myFetch = async function() {
    const response = await fetch('/api/characters/5');

    const data = await response.json();

    document.querySelector('.container').textContent = data.name;
    }

    myFetch();
  • .catch() works the same way when you use async/await but you define it when you invoke the async function:

    // Define an async function
    const myFetch = async function() {
    let response = await fetch('/api/characters/5');

    // An exception thrown by the developer
    if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
    }

    let data = await response.json();

    document.querySelector('.container').textContent = data.name;
    }

    // Invoke an async function
    myFetch().catch(function(error) {
    console.log(error);
    });
    • Note: fetch() only throws an exception when there's a network error (i.e. domain not found), not when there's a 404 Not Found error.

2. Exceptions and try/catch blocks

Terminology

Exceptions
An error that produces an error object that can be "handled" by the Javascript engine. Exceptions can be "thrown" when Javascript encounters a runtime error or if the developer explicitly throws an exception.
Throwing an Exception
Producing an error object.
Exception Handling
Doing something with an exception instead of moving to the next statement in the code. Also called "catching" errors.

Materials

Key Takeaways

  • Exceptions can only be thrown by runtime errors. Syntax errors cannot throw exceptions because the code can't run in the first place.

  • A common way to handle exceptions is to wrap your code in a try/catch block.

  • With asynchronous code, try/catch is often used with async/await instead of using a .catch() block.

     // Define an async function
    const myFetch = async function() {
    try {
    let response = await fetch('/api/characters/5');

    let data = await response.json();

    document.querySelector('.container').textContent = data.name;
    } catch(error) {
    console.log(error);
    }
    }

    // Invoke an async function
    myFetch();
  • The developer can throw Exceptions explicitly with throw new Error():

     // Define an async function
    const myFetch = async function() {
    try {
    let response = await fetch('/api/characters/5');

    let data = await response.json();

    document.querySelector('.container').textContent = data.name;
    } catch(error) {
    console.log(error);
    }
    }

    // Invoke an async function
    myFetch();

Activity

Refactor Assignment 3 so that it uses async/await with a try/catch block instead of .then()/.catch().


3. Mongoose GET requests with async/await

Materials

Key Takeaways

  • Since all our Mongoose code will be inside a function passed to our method handler, we place the async keyword in front of it.

    app.get('/api/cats', async (request, response) => {
    response.send('This is asynchronous!');
    })
  • Once your Mongoose code is inside an async function, you use the await keyword whenever you invoke a Mongoose method (because all Mongoose functions use Promises when you don't pass it a callback function as an optional parameter).

    const catSchema = new mongoose.Schema({name: String})
    const Cat = mongoose.model('Cat', catSchema);

    app.get('/api/cats', async (request, response) => {
    const data = await Cat.find();
    response.send(data);
    })
  • Since app.get() invokes our callback function for us, it's difficult (impossible) to attach a .catch() method (for Promises) on the end of it. Instead, we use a try/catch block to handle any problems we might have with Atlas:

    const catSchema = new mongoose.Schema({name: String})
    const Cat = mongoose.model('Cat', catSchema);

    app.get('/api/cats', async (request, response) => {
    try {
    const data = await Cat.find();
    response.send(data);
    } catch(error){
    console.log('Caught an error!', err)
    response.send({error: 'Uh oh, there was an error'})
    }
    })

Lab Time

  • Trophy of the day
  • Assignment 5
  • Final Project

Prep

Introduction to CRUD and Mongoose

POST Requests in Express

Stretch Gists: