I’m fairly new to node, but there was a feature I was really missing, and that’s async/await which I think makes Node.js much less cluttered with boilerplate syntax than using callbacks or promises.
When I first tried to use it I got a syntax error. Of course! I should have noticed that the version of Node.js that AWS Lambda currently supports (6.10.3) doesn’t include async/await.
Surely there’s an easy way to get async/await to work with Serverless?
What are callbacks, promises and async/await anyway?
Callbacks came first, then Promises (in their various guises) then finally async/await. It looks like quite a bit of a mess to anyone who’s coming fresh to Node.js, but on the other hand, I’ve been using a similar feature in C# since 2012, and it’s not really any different to the situation there - delegates / event handlers for handling events in the early days (callbacks), then later lambda expressions and
Task were added (promises), then the language got async / await on top to make the code clearer.
Since there’s 3 ways of achieving the same objective, Node.js libraries use all of the different mechanisms depending on how old they are.
This blog was also handy to guide me in how I could convert code I’d written which used callbacks to using promises. https://benmccormick.org/2015/12/30/es6-patterns-converting-callbacks-to-promises/
Once I had my code using Promises, I wanted to step up to async/await to simplify more. Since I can’t update Node.js on AWS, I’d need to update my code somehow.
Babel steps up
I didn’t find Babel’s documentation particularly helpful, and a lot of the suggestions on Stackoverflow etc. are out-of-date with current best practice, but thanks to a few issues and questions on Stackoverflow, I worked out what I needed to do:
- Install Babel into my project (
npm install --save-dev babel-cliand
npm install --save-dev babel-preset-env)
.babelrcfile to tell Babel what rules to apply (in my case, compile to the version of node that the current environment is using - which I’ve also set to be the same version that AWS Lambda uses)
- You’ve got to be careful here. If the Node.js version on the machine that’s transpiling the code is newer than the target version, then Babel won’t do the correct operations.
packages.jsonto add scripts in to:
Run the Babel executable against my Node.js code
- Ignore the node_modules folder so that it doesn’t attempt to transpile everything.
- Ignore the output folder.
Run tests against the newly transpiled output.
Update the Serverless.yml to use the transpiled output (under the /lib directory) which is compatible with the AWS Node.js version.
Here’s some slightly simplified down versions of what that looks like:
Migrating the code to use async/await
Once I had support for it, I needed to refactor my code. Here’s an example of the process I used to migrate some code I wrote to read from Google’s Geolocation API and parse the output into a Location class.
The last file shows that it’s important to note that the API surface changes when migrating from callbacks to Promises, so calling code will be needed for that, just not from when migrating to async / await.
I think it’s worth the effort of back-porting async/await to AWS Lambda to make code much easier to read, despite the added complication of a build step.