When building applications in Node/Express you will quickly come to realize that everything is done asynchronously . But how you accomplish these tasks async can vary. The ‘old school’ way was to use call backs, which often led to callback hell. Than came along Promises which we thought was going to solve all the worlds problems, turned out they helped, but did not solve everything. Finally in Node 8.0 (ok, you could use them in Node 7.6) the support for async/await was introduced and this really has cleaned up and enhanced the readability of your code.
Having the ability to use async/await is great, and is supported out of the box w/ Express. But what do you do when you using a library which still wants to use promises or callbacks? The case in point for this article is AWS Node SDK.
By default if you read through the AWS SDK documentation the examples lead you to believe that you need to use callbacks when implementing the SDK. Well this can really lead to some nasty code in the world of Node/Express. However, as of v2.3.0 of the AWS SDK there is support for Promises. This is much cleaner than using callbacks, but still poses a bit of an issue if you want to use async/await in your Express routes.
However, with a bit of work you can get your promise based AWS calls to play nicely with your async/await based Express routes. Lets take a look at how we can accomplish this.
Before you get started I am going to make a few assumptions.
- You already have a Node/Express application setup
- You already have the AWS SDK for Node installed, if not read here
The first thing we are going to need to do is add reference to our AWS SDK and configure it to use promises.
const AWS = require('aws-sdk'); AWS.config.setPromisesDependency(null);
After we have our SDK configured we can implement our route handler. In my example here I am placing all the logic inside my handler. In a real code base I would suggest better deconstruction of this code into smaller parts.
const express = require('express'); const router = express.Router(); const s3 = new AWS.S3(); router.get('/myRoute', async (req, res) => { const controller = new sitesController(); const params = req.params; const params = { Bucket: "bucket_name_here" }; let results = {}; var listPromise = s3.listObjects(params).promise(); listPromise.then((data) => { results = data; }); await Promise.all([listPromise]); res.json({data: results }) }) module.exports = router;
Lets review the code above and call out a few important items.
The first thing to notice is the addition of the async
keyword in my route handler. This is what allows us to use async/await in Node/Express.
The next thing to look at is how I am calling the s3.listObjects. Notice I am NOT providing a callback to the method, but instead I am chaining with .promise(). This is what instructs the SDK to use promises vs callbacks. Once I have my callback I chain a ‘then’ in order to handle my response.
The last thing to pay attention to is the line with await Promise.All([listPromise]);
This is the magic forces our route handler to not return prior to the resolution of all of our Promises. Without this your call would exit prior to the listObjects call completing.
Finally, we are simply returning our data from the listObjects call via res.json
call.
That’s it, pretty straight forward, once you learn that the AWS SDK supports something other than callbacks.
Till next time,