Koa Through Example: Part 1
While I do not have a lot of pain points using Express, I thought it was important to learn about what is being called a more robust foundation for web applications.

TL;DR: Wrote this article as I was learning Koa; considered switching from Express to it. In the end, I did not find a compelling reason to switch. You may come to a different conclusion.
I came around to learning the ES2017 / ES8 feature async / await feature because I recently saw it being used in a mainstream JavaScript library; Koa.
Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs.
— Koa Team
I wrote a separate article on async / await if you are interested: My Journey to Using Async / Await. Having embraced async / await, I thought I would turn attention back to Koa itself.
All the examples in this series are available for download. Also, you will want to run them using a newer version of Node.js (say version ≥ 8.9.4).
First Express
Before diving into Koa, I thought to explore how my new-found skills with async / await could help with Express.
First I wrote a web application that makes multiple asynchronous calls before sending the response using a traditional approach.
express-promise/index.js
/* eslint-disable no-console */
const express = require('express');const myAsync = () => new Promise(resolve => setTimeout(resolve, 1000, 'Hello World!'));
const app = express();
app.get('/', (req, res) => {
const body = [];
myAsync()
.then(value => body.push(value))
.then(myAsync)
.then(value => body.push(value))
.then(() => res.send(body.join(' ')));
});
app.listen(3000, () => console.log('Example app listening on port 3000!'));
Observations:
- 2 seconds after the request, the server responds with Hello World! Hello World!.
- Because we are using promises, the code is fairly clean (we do not have deep nesting).
The following web application behaves the same; just uses async / await to simplify the promise calls (an improvement in readability in my view).
express-async/index.js
/* eslint-disable no-console */
const express = require('express');const myAsync = () => new Promise(resolve => setTimeout(resolve, 1000, 'Hello World!'));
const app = express();
app.get('/', async (req, res) => {
const body = [];
body.push(await myAsync());
body.push(await myAsync());
res.send(body.join(' '));
});
app.listen(3000, () => console.log('Example app listening on port 3000!'));
Next Koa
Let us look at the same example using Koa.
koa-async/index.js
const Koa = require('koa');const myAsync = () => new Promise(resolve => setTimeout(resolve, 1000, 'Hello World!'));
const app = new Koa();
app.use(async (ctx) => {
const body = [];
body.push(await myAsync());
body.push(await myAsync());
ctx.body = body.join([' ']);
});
app.listen(3000);
Observations:
- The code does not look much different than the Express example using async / await.
- Unlike Express, Koa does not have routing built in; you have to use third-party middleware for that.
What is the Big Deal?
At this point, you are likely thinking (like I did) what the benefit of Koa is over Express. Looking deeper into the Koa documentation, you will find this passage:
Koa middleware cascade in a more traditional way as you may be used to with similar tools — this was previously difficult to make user friendly with node’s use of callbacks. However with async functions we can achieve “true” middleware. Contrasting Connect’s implementation which simply passes control through series of functions until one returns, Koa invoke “downstream”, then control flows back “upstream”.
— Koa Team
When I first read this, I thought What the heck is this downstream and upstream business?
Next Steps
In the next article, Koa Through Example: Part 2, we begin to unpack the meaning of downstream and upstream through example.