Koa in 10 Minutes

In this article we will explore web service development using Koa. We will also look at some of the really cool things about Koa.

Koa is a generator based framework. Generators simplify asynchronous programming by not using callbacks and using language constructs like yield.

Note: Koa 2 has moved to a async/await based approach from the legacy generator based approach. At the time of this writing Koa 2 is still in alpha stage.

In the example below we will develop a web service that itself consumes an outside web service. This will give us a taste for asynchronous programming in Koa.

Setup the Project

Inside a clean folder initialize a Node project.

npm init

Accept all defaults.

Install the required packages.

npm install koa koa-request koa-router@4.3.2 --save

Note: The latest koa-router package has already moved to Koa 2. As a result we choose to install an older version.

Write the Web Service

Create a file called my_app.js.

Import the necessary packages.

var koa = require('koa');
var http_client = require('koa-request');
var router = require('koa-router')();

Set up a route handler for the "/example" path.

router.get("/example", function *() {

    var options = {
        url: 'https://httpbin.org/get',
        headers: { 'User-Agent': 'Micky Mouse' }
    };

    var response = yield http_client(options); 
    var info = JSON.parse(response.body);

    this.body = info;
});

Notice a few things:

  1. We supply a generator function to router.get(). A generator function is able to suspend its execution midway while it waits for an asynchronous operation.
  2. We use the yield keyword to wait for the HTTP call to complete. The function suspends execution at this point. It resumes again once the HTTP call completes.

Finally, add this code to register the router and start the server.

var app = koa();

app
  .use(router.routes())
  .use(router.allowedMethods());

app.listen(8080);

Start the app:

node my_app.js

Send a request.

curl -v localhost:8080/example

Error Handling

One of the most appealing features of Koa is error handling from asynchronous code. In Express, an unhandled exception thrown from an asynchronous call back function will terminate the Node process. This is completely unacceptable for a server. As a result you have to be super diligent about catching all possible exception scenarios. This is easier said than done in an untyped programming language like Javascript. Koa on the other hand handles all exceptions thrown from generators. For example, we can introduce an error in our code by using a bogus host name for the web service call.

var options = {
    url: 'https://bad.httpbin.orgcom/get',
    headers: { 'User-Agent': 'Micky Mouse' }
};

Restart the server and send another request. You will see a log message on the server’s console.

  Error: getaddrinfo ENOTFOUND bad.httpbin.orgcom bad.httpbin.orgcom:443
      at errnoException (dns.js:28:10)
      at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)

The client will get a 500 error code back.

Doing Sequential Asynchronous Operations

Making sequential calls are super easy. Below we make two HTTP calls in sequence.

router.get("/example", function *() {

    console.log("Making sequential async calls.")

    var call1 = {
        url: 'http://httpbin.org/delay/10'
    };

    var response1 = yield http_client(call1);

    var call2 = {
        url: 'http://httpbin.org/delay/10'
    };

    var response2 = yield http_client(call2);

    console.log("Received all responses from sequential async calls.")

    console.log(response1)
    console.log(response2)

    this.body = "Yakushima! Great success!";
});

Each call takes 10 seconds. So the whole thing will take about 20 seconds.

Doing Parallel Asynchronous Operations

You can start multiple asynchronous operations and wait for them all to finish. This is called the scatter gather pattern. ES6 makes it as simple as it can be.

router.get("/example", function *() {

    var call1 = {
        url: 'http://httpbin.org/delay/10'
    };
    var call2 = {
        url: 'http://httpbin.org/delay/10'
    };

    console.log("Making parallel async calls.")

    var [response1, response2] = yield [
        http_client(call1),
        http_client(call2)]; 

    console.log("Received all responses from parallel async calls.")

    console.log(response1)
    console.log(response2)

    this.body = "Yakushima! Great success!";
});

Now the entire operation will take about 10 seconds.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s