Koa Generators

Introduction

My last post went through the slight differences between Express and Koa. This post will focus on Koa's use of generators and the yield keyword.

Simple Server

We are going to start by creating a simple server with Koa (index.js):

var app = require('koa')();

app.use(function* firstMiddleware(next) {  
  this.body = 'In first middleware.';
  yield next;
});

app.listen(3000, () => {  
  console.log('Listening on localhost:' + 3000);
});

If we were to run this example as-is via node --harmony index.js, the server would respond with a basic page with some text 'Hello world'. You may have noticed the use of this.body as opposed to this.response.body in previous examples. Many of Koa's accessors and methods delegate to their request or response objects. In this case, the use of this.body delgates to this.response.body. You can find a list of request aliases here and a list of response aliases here.

Yield Keyword

You may also notice the yield keyword. The yield keyword allows us to make asynchronous calls in a semi-synchronous way. In this example, yield next; will delegate to the next middleware in the chain. Let's add another middleware for example:

var app = require('koa')();

app.use(function* firstMiddleware(next) {  
  this.body = 'In first middleware.';
  yield next;
});

app.use(function* secondMiddleware() {  
  this.body += '\nIn second middleware.';
});

app.listen(3000, () => {  
  console.log('Listening on localhost:' + 3000);
});

If we run this example, we will see an output of:

In first middleware.  
In second middleware.  

When we yield to the next middleware (downstream) that middleware will be run. The cool thing about yielding downstream is that, eventually, we will return back UPstream. Take this example:

var app = require('koa')();

app.use(function* firstMiddleware(next) {  
  this.body = 'In first middleware.';
  yield next;
  this.body += '\nBack in first middleware.';
});

app.use(function* secondMiddleware() {  
  this.body += '\nIn second middleware.';
});

app.listen(3000, () => {  
  console.log('Listening on localhost:' + 3000);
});

If we run this example, we will see the following output:

In first middleware.  
In second middleware.  
Back in first middleware.  

Our first middleware yields downstream (in this case, to the next middleware in Koa's middleware chain). The second middleware executes, and then flows back upstream to the point at which it was yielded. The first middleware then resumes execution.

We can continue this pattern for as long as we want through the middleware chain:

var app = require('koa')();

app.use(function* firstMiddleware(next) {  
  this.body = 'In first middleware.';
  yield next;
  this.body += '\nBack in first middleware.';
});

app.use(function* secondMiddleware(next) {  
  this.body += '\nIn second middleware.';
  yield next;
  this.body += '\nBack in second middleware.';
});

app.use(function* thirdMiddleware() {  
  this.body += '\nIn third middleware.';
});

app.listen(3000, () => {  
  console.log('Listening on localhost:' + 3000);
});

Will output:

In first middleware.  
In second middleware.  
In third middleware.  
Back in second middleware.  
Back in first middleware.  

We can stop the chain simply by not yielding to next; any middleware added after our third middleware will not execute in this case.

Conclusion

We can see how powerful generators are in Koa when used as middleware. Coupled with middleware contexts, Koa provides us a clean and efficient alternative to Express.

As Koa is utilizes co, there are plenty of available node modules that allow you to utilize generators. e.g. filesystem, views, and body parsing among many others.

As always, you can view the files used in this project on CraterDust's GitHub.