Applying the callback -> async/await conversion process to a real-world example
Tags: javascript, node
Published: 2019-03-05 04:08:07

---
title: Applying the callback -> async/await conversion process to a real-world example
published: true
tags: javascript,nodejs
canonical_url: https://www.coreycleary.me/applying-the-callback-async-await-conversion-process-to-a-real-world-example/
---
<em><strong>Originally published at <a href="https://www.coreycleary.me/applying-the-callback-async-await-conversion-process-to-a-real-world-example/">coreycleary.me</a></strong>. This is a cross-post from my content blog. I publish new content every week or two, and you can <a href="https://www.coreycleary.me/about/">sign up to my newsletter</a> if you'd like to receive my articles directly to your inbox! I also regularly send cheatsheets and other freebies.</em>

This is a follow-up to my <a href="https://www.coreycleary.me/how-to-rewrite-a-callback-function-in-promise-form-and-async-await-form-in-javascript/" rel="noopener" target="_blank">post on the process for converting callbacks to Promises and to `async/await` functions</a>. 

In that post I stuck to using `setTimeout` as an easy way to introduce some asynchronicity into the code. But I understand that for some people, they need more real-world examples to read and play around with in order to truly get the concept to click.

So that post was more about the process, and this one is more about implementation. In this post we'll skip promises and go directly from callback to `async/await`.

<h3>The callback version</h3>
Our scenario is that we need to:
<ul>
<li>loop over a list of book titles</li>
<li>for each one, make a request to the <a href="https://openlibrary.org/developers/api" rel="noopener" target="_blank">Openlibrary API</a> with book title</li>
<li>get isbn from Openlibrary</li>
<li>insert isbn number and book title into 'books' table</li>
</ul>

Here's the code using callbacks, this is what we'll be converting:
```javascript
const request = require('superagent')
const { Client } = require('pg')

const titles = ['Gullivers Travels', 'Gravitys Rainbow']

const getISBN = (bookTitle, callback) => {
  return request
    .get('http://openlibrary.org/search.json')
    .query({q: bookTitle})
    .end((err, res) => {
      if (err) return callback(new Error(`Error calling OpenLibrary: ${err}`))
      if (res.status === 200) {
        const parsed = JSON.parse(res.text)
        const first_isbn = parsed.docs[0].isbn[0]
        return callback(null, first_isbn)
      }
    }
  )
}

const getConnection = () => {
  return {
    host: 'localhost',
    database: 'books',
    password: null,
    port: 5432,
  }
}

const insert = (tableName, bookTitle, isbn, callback) => {
  const client = new Client(getConnection())
  client.connect()

  client.query(`INSERT INTO ${tableName} (bookTitle, isbn) VALUES ('${bookTitle}', '${isbn}');`, (err, res) => {
    if (err) callback(new Error(`Error inserting: ${err}`))
    else callback(null, res)
    client.end()
  })
}

// loop over titles
for (const bookTitle of titles) {
  // make request to openlib with book title
  // get isbn from openlib
  getISBN(bookTitle, (err, res) => {
    if (err) {
      console.log('Hit an error calling OpenLibrary API', err)
    } else {
      const isbn = res
      // add isbn number and book title to table
      insert('books', bookTitle, isbn, (err, res) => {
        if (err) {
          console.log('Hit an error inserting into table', err)
        } else {
          console.log(`${bookTitle}, ISBN: ${isbn} added to books table`)
        }
      })
    }
  })
}
```

<h3>Applying the process</h3>
Let's start applying the process.

We'll start with the `getISBN` function:

<img src="https://www.coreycleary.me/wp-content/uploads/2019/02/cb-getjson.png" alt="" width="705" height="675" class="aligncenter size-full wp-image-980" />

Then the `insert` function, for inserting into the database:

<img src="https://www.coreycleary.me/wp-content/uploads/2019/02/cb-insert.png" alt="" width="990" height="560" class="aligncenter size-full wp-image-981" />

And now, the "main" function that executes our logic:

<img src="https://www.coreycleary.me/wp-content/uploads/2019/02/cb-run-1.png" alt="" width="647" height="737" class="aligncenter size-full wp-image-991" />

One thing to note here for this last bit of code, for the `async/await` version is that if there is an error in the `getJSON` function call, it will be caught by the `catch(e)` block and the function will exit. The `insert` function won't be called. We could have wrapped each await call in its own try/catch too, if we wanted to avoid this behavior. It just depends on the needs of the code/feature you're working on.

<h3>After - async/await</h3>
Here's the complete `async/await` version:
```javascript
const request = require('superagent')
const { Client } = require('pg')

const titles = ['Gullivers Travels', 'Gravitys Rainbow']

const getISBN = async (bookTitle) => {
  let response

  try {
    const apiResponse = await request
      .get('http://openlibrary.org/search.json')
      .query({q: bookTitle})
    
    const parsed = JSON.parse(apiResponse.text)
    response = parsed.docs[0].isbn[0]
  } catch(e) {
    throw new Error(`Error calling OpenLibrary: ${e}`)
  }

  return response
}

const getConnection = () => {
  return {
    host: 'localhost',
    database: 'books',
    password: null,
    port: 5432,
  }
}

const insert = async (tableName, bookTitle, isbn) => {
  const client = new Client(getConnection())
  await client.connect()

  let res
  
  try {
    res = await client.query(`INSERT INTO ${tableName} (bookTitle, isbn) VALUES ('${bookTitle}', '${isbn}');`)
  } catch(e) {
    throw new Error(`Error inserting: ${e}`)
  }

  await client.end()
  return res
}

const run = (async () => {
  for (const bookTitle of titles) {
    try {      
      // make request to openlib with book title
      // get isbn from openlib
      const isbn = await getISBN(bookTitle)

      // add isbn number and book title to table
      await insert('books', bookTitle, isbn)
      console.log(`${bookTitle}, ISBN: ${isbn} added to books table`)
    } catch(e) {
      throw new Error(e)
    }
  }
})()
```

<h3>Wrapping up</h3>
If the first post didn't help things click for you, hopefully seeing an example like this one did.

The next time you need to convert callbacks, apply <a href="https://www.coreycleary.me/how-to-rewrite-a-callback-function-in-promise-form-and-async-await-form-in-javascript/" rel="noopener" target="_blank">this process</a> and reference the post here in order to more easily grasp how to move away from callbacks!

I'm writing a lot of new content to help make Node and JavaScript easier to understand. Easier, because I don't think it needs to be as complex as it is sometimes. If you enjoyed this post and found it helpful <a href="https://www.coreycleary.me/about/">here's that link again</a> to subscribe to my newsletter!