Hemanth.HM

A Computer Polyglot, CLI + WEB ♥'r.

Getting Started With Koajs

| Comments

koa next generation web framework for node.js brought to us by the wonderful team behind express {Specially bow to TJ}.

Let's being with a simple hello-world application :

First up Express:

1
2
3
4
5
6
7
8
9
var express = require('express');

var app = express();

app.use(function(req, res, next){
  res.send('Hello World');
});

app.listen(3000);

Here comes koa:

1
2
3
4
5
6
7
8
var koa = require('koa');
var app = koa();

app.use(function *(){
  this.body = 'Hello World';
});

app.listen(3000);

Both of the above code will result in a HTTP server listening on port 3000 and would render 'Hello World' for the index.

If you are wondering what on earth is function *(){} is they are harmony:generators and we can use ES6 on node today with node --harmony flag as of now.

Let's zoom in a bit:

1
2
3
4
5
6
7
8
9
// Express
app.use(function(req, res, next){
  res.send('Hello World');
});

//Koa
app.use(function *(){
  this.body = 'Hello World';
});

Seeing this for the first time you might wonder where the hell are the req and res params!

The answer is the context. A Koa Context encapsulates node's request and response objects into a single object.

A Koa application is an object containing an array of middleware generator functions which are composed and executed in a stack-like manner upon request

So, for every request a new context is created:

1
2
3
4
5
6
7
app.use(function *(){
  this; // is the Context
  this.request; // is a koa Request.
  this.response; // is a koa Response.
  this.req; // nodejs request.
  this.res; // nodejs response.
});
1
2
3
4
5
6
7
8
9
10
// keys of this:
[ 'request',
  'response',
  'app',
  'req',
  'res',
  'onerror',
  'originalUrl',
  'cookies',
  'accept' ]

If we were to re-rewrite Koa hello world example with route it would be like:

1
2
3
4
5
6
7
var koa = require('koa');
var app = koa();
var route = require('koa-route');

app.use(route.get('/', function *() {}
    this.body = 'Hello World';
));

So, there are set of route middlewares and their respective middleware definitions and each have their own contexts.

In express it would be like:

1
2
3
4
5
6
var express = require('express');
var app = express();

app.get('/', function(req, res){
  res.send('hello world');
});

Enough of hello-world, let's dig into the real power of generators in Koa!

With the help of ES6 generators it's uber easy and intuitive, have a look at the below example straight from Koa docs!

koa

In the code above each yield next will make the to control to flow "downstream" from the "upstream" and finally where there are no more middlewears left the stack will unwind.

It's as good as the generator suspends and passes the flow to the downstream and then resumes.

The flow is like mw1->mw2->mw3 and backwards mw3->mw2->mw1

If you had cascaded multiple middlewares in Express which uses Connect's implementation which simply passes control through series of functions until one returns, which can get really messy with callback hell!

But with Koa, it's as easy as:

1
2
3
4
5
function *all(next) {
  yield mw1.call(this, mw2.call(this, mw3.call(this, next)));
}

app.use(all);

Note the pattern is just chaining the required .call(this, next)

This can further be simplified with koa-compose

1
2
3
4
5
6
7
8
9
var co = require('co');
var compose = require('koa-compose');

co(function *(){
      yield compose(stack)
})(function(err){
      if (err) throw err;
      done();
})

Well there are few many things you can do like streaming file, object or views to this.body and more, summarizing it:

  • No more callback hell, thanks to generated-based control flow.
  • Koa is a minimalistic framework which does not include routing, middleware or extra utils.
  • Relies less middleware thanks to the wonderful context!
  • Better stream handling and abstracts node's req and res.

Hope this helped you get started with Koa! Don't miss to read their wonderful wiki

Comments