Skip to main content

First steps with Koa.js

 When it comes to web development, chances are you’re going to pick up a framework to get your backend API up and running. Aside from Node having good built-in mechanisms for the construction of web servers, frameworks, on the other side, facilitate this job by providing nice features like middleware, routing mechanisms, etc.

Express is by far the leader in terms of web development in the Node.js universe. It’s also the oldest, created back in 2009, which is perhaps one of the reasons that made it mature enough to be so beloved by the community.

Koa.js is another great option that’s been gaining more and more space. But they are actually not competitors. Koa was designed by the same team behind Express, which is a common trend in the frontend community, take Deno, for example, whose creator was the same mind behind Node.

Koa was created to be smaller, faster, and more expressive in terms of coding. When it comes to the development of web APIs, Express is great, but it lacks a bit of expressiveness and still leads us to commit some boilerplate code that could be avoided, as we’re going to see in practice in a few minutes.

It was designed with a big focus on async functions, making them simpler so you can manipulate callbacks and handle the errors of your code flows more easily.

At the end of this post, we will have an app that retrieves information from a Koa-based API using some nice features of the framework. The mock data is going to be retrieved from the fake data generation website called https://randomuser.me/. So, let’s dive into it!

Setup and configuration

Like everything else in the Node universe, setting things up is fast and easy. Make sure that you have Node installed, choose a folder of your preference for the development of this example, and run the following commands into it:

npm init
npm i koa koa-router koa-ejs axios

Fill in the information that the command line is going to ask you about your Node project. I left all of them blank, but feel free to inform anything that you want.

The first three dependencies are Koa-related, being the first one at the heart of the framework.

The koa-router is the Express routing system equivalent. Yes, it comes within a second package that needs to be added to your package.json separately.

Koa-ejs is a bonus. It is a Koa middleware that adds support to all features of the ejs project. This way, we can embed JavaScript templates within our backend web app without the need for a client project. In other words, it renders the HTML output of our web pages.

Finally, the famous Axios library is here because we need to call an external API, the randomuser.me.

Now, go ahead and create a new index.js file at the root of your project. Place the following code into it:

const koa = require("koa");
const path = require("path");
const render = require("koa-ejs");
const koaRouter = require("koa-router");
const axios = require("axios");

const app = new koa();
const router = new koaRouter();

render(app, {
    root: path.join(__dirname, "views"),
    layout: "index",
    viewExt: "html",
});

router.get("hello", "/", (ctx) => {
    ctx.body = "<h1>Hello World, Koa folks!</h1>";
});

router.get("users", "/users", async (ctx) => {
    const result = await axios.get("https://randomuser.me/api?results=5");

    return ctx.render("index", {
        users: result.data.results,
    });
});

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

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`running on port ${PORT}`));

The first few lines of this listing relate to the imports of the dependencies we’ve just installed. Both the main Koa and its router objects need to be instantiated through the new operator.

The render function, from koa-ejs, is here to delineate the parameters of our ejs template system (still to be built). The first param it receives is the Koa app object recently created, and the second is another object containing information like the root folder in which the ejs templates are placed, the layout main file, and the extension of those files (HTML). This is the most basic configuration, but you can find the other available parameters here.

Next, we get two endpoints created. The first is just a simple Hello World mapped to the root endpoint, while the second is a bit more complex and returns the list of random users attached to the template input.

Notice how similar it is to route endpoints on Koa and Express. The first param asks for a canonical name for your endpoint, and the second requires the path string that maps to this endpoint. The main difference is within the callback function (the third param) that deals with the response handling, which is manipulated by the ctx object, the Koa Context.

The Koa Context embraces both Node’s request and response objects into a single one, which simplifies the approach, differently from what Express does. Since they’re used so frequently, the Koa creators found that would be better to stick together:

app.use(async ctx => {
  ctx; // This is the context
  ctx.request; // This is a Koa request
  ctx.response; // This is a Koa response
});

There’s no need, however, to always call the request or response objects individually to access their properties. If you want to access the request’s body, for example, just do it directly:

ctx.body; // It delegates to Koa’s ctx.request

Koa magically delegates the access of any property to their respective equivalents, just for convenience.

Koa also allows you to decide if you want to work with async functions or not. Let’s take the second endpoint as an example. Note that we’re calling an external URL within its callback function to get the random users array and send it directly to our koa-ejs template (we’ll build it in a few minutes).

This is a much cleaner approach compared to the promise-based Express one. With Express, we’d have something like that:

app.get('/users', (req, res, next) => {
  axios.get("https://randomuser.me/api?results=5").then((result) => {
    res.status(200).json(result.data.results);
  }).catch((err) => next(err));
});

It may look okay at first sight, because the example is simple. However, if your development gets more complex, like with the adding of a data retrieval from a database, things can become tricky:

app.get('/users', (req, res, next) => {
  MyDatabaseObj.findByPk(myPk).then(data => 
    if (!data) {
      return res.status(404).send({});
    }

    axios.get("https://randomuser.me/api?results=5&id=" + data.id).then((result) => {
      res.status(200).json(result.data.results);
    }).catch((err) => next(err));    
  );
});

This style can lead developers to nest many code blocks, which are hard to maintain.

Back to the index.js code, the rest of it is very similar to what you do with Express. The Koa middleware must be stated via use() method. To get the server up and running, just start it via listen() method. Very similar, isn’t it?

The template

Now that we’ve finished with the API creation, let’s move on to the ejs template. First, you need to create a new folder called views at the root of your project. And inside of it, create the main file called index.html.

Since breaking down the template system in minimal pieces is not the focus of the article, we’re going to stick to a single file as our template. This is the code you should add to it:

<html>
    <head>
        <title>First Steps with Koa</title>
        <link
            rel="stylesheet"
            href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
        />
    </head>
    <body>
        <div class="container">
            <div class="pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
                <h1 class="display-4">Koa.js</h1>
                <p class="lead">
                    A simple list of users retrieved from
                    <a href="https://randomuser.me/">randomuser.me</a>
                </p>
            </div>

            <div class="list-group">
                <% users.forEach( function(user) { %>
                <div class="list-group-item">
                    <div class="d-flex w-100 justify-content-between">
                        <h5 class="mb-1">
                            <%= user.name.title %> <%= user.name.first %> <%= user.name.last
                            %>
                        </h5>
                        <small
                            >Registered at: <%= new
                            Date(user.registered.date).toISOString().split('T')[0] %></small
                        >
                    </div>
                    <p class="mb-1">
                        <strong>Address:</strong>
                        <%= user.location.street.number %> <%= user.location.street.name
                        %>, <%= user.location.city %> <%= user.location.postcode %> - <%=
                        user.location.country %>
                    </p>
                    <small>Phone: <%= user.phone %></small>
                </div>
                <% }); %>
            </div>
        </div>
    </body>
</html>

Notice that it’s plain HTML, so nothing new here. Right at the beginning, within the head tag, we’re adding the Bootstrap’s CSS stylesheet. It’ll help to input styling to our example page.

The koa-ejs library makes use of expressions to separate what’s HTML from what’s JavaScript code.

Whenever you want to open a new JavaScript code block, wrap the code with the <% ... %> operators. Otherwise, if you want to print some value directly into the HTML, use the <%=  %> operators. Just remember that, like any other JavaScript code block, your blocks need to open and close properly, like as you usually do within JavaScript code files.

Go ahead and have a look over the iteration we’re doing. It’s plain JavaScript code, pretty simple.

Now, let’s test it. Run the application by issuing the node index.js command on your console and type the http://localhost:3000/ address at your browser. This will produce the following output:

Hello world, koa folks!

Then, go ahead and change the address to http://localhost:3000/users. You may see the list of users changing every time you refresh the browser.

populated list of random users
What about the errors?

Errors are a very important part of your web applications. Although you can always handle them individually on each endpoint, and just like with Express, Koa also allows you to create a centralized middleware to deal with your app errors.

Look at the following code snippet:

app.use(async (ctx, next) => {
    try {
        await next();
    } catch (err) {
        console.error(err);
        ctx.body = "Ops, something wrong happened:<br>" + err.message;
    }
});

This middleware must be placed before all the others, so you can grab and log any kind of error your app may face, including the ones related to the other middleware.

If you have more than one JavaScript file in which endpoints are mapped, you can centralize this middleware in one place and export it to all of them.

What about the logs?

Yes, Koa also has another package that deals with more fine-grained logging mechanisms for development and debugging.

For this, you need first to install the proper dependency:

npm i koa-logger

And add the following content to your index.js:

// At the beginning of the file
const Logger = require("koa-logger");

...

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

Make sure that the Logger middleware is also the first one to be added, otherwise, Koa won’t listen to the logs from your routes and HTTP calls.

When you restart your app and access the endpoints again, you may see logs similar to the ones below:

Conclusion

This was just a brief introduction to the powers of Koa.js and how it can make things clearer when it comes to code organization. To see more of its benefits, the use of common frameworks like Sequelize for database handling, Jasmine for testing, etc. is a must, or perhaps you may test its inclusion right into your current project. Just create a fork and go for it!

Koa also offers support for a bunch of additional features like CSRF and JWT (JSON Web Tokens), access logs, charset conversions, caching, minifiers and

Comments

Popular posts from this blog

4 Ways to Communicate Across Browser Tabs in Realtime

1. Local Storage Events You might have already used LocalStorage, which is accessible across Tabs within the same application origin. But do you know that it also supports events? You can use this feature to communicate across Browser Tabs, where other Tabs will receive the event once the storage is updated. For example, let’s say in one Tab, we execute the following JavaScript code. window.localStorage.setItem("loggedIn", "true"); The other Tabs which listen to the event will receive it, as shown below. window.addEventListener('storage', (event) => { if (event.storageArea != localStorage) return; if (event.key === 'loggedIn') { // Do something with event.newValue } }); 2. Broadcast Channel API The Broadcast Channel API allows communication between Tabs, Windows, Frames, Iframes, and  Web Workers . One Tab can create and post to a channel as follows. const channel = new BroadcastChannel('app-data'); channel.postMessage(data); And oth...

Certbot SSL configuration in ubuntu

  Introduction Let’s Encrypt is a Certificate Authority (CA) that provides an easy way to obtain and install free  TLS/SSL certificates , thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, Certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated on both Apache and Nginx. In this tutorial, you will use Certbot to obtain a free SSL certificate for Apache on Ubuntu 18.04 and set up your certificate to renew automatically. This tutorial will use a separate Apache virtual host file instead of the default configuration file.  We recommend  creating new Apache virtual host files for each domain because it helps to avoid common mistakes and maintains the default files as a fallback configuration. Prerequisites To follow this tutorial, you will need: One Ubuntu 18.04 server set up by following this  initial ...

Working with Node.js streams

  Introduction Streams are one of the major features that most Node.js applications rely on, especially when handling HTTP requests, reading/writing files, and making socket communications. Streams are very predictable since we can always expect data, error, and end events when using streams. This article will teach Node developers how to use streams to efficiently handle large amounts of data. This is a typical real-world challenge faced by Node developers when they have to deal with a large data source, and it may not be feasible to process this data all at once. This article will cover the following topics: Types of streams When to adopt Node.js streams Batching Composing streams in Node.js Transforming data with transform streams Piping streams Error handling Node.js streams Types of streams The following are four main types of streams in Node.js: Readable streams: The readable stream is responsible for reading data from a source file Writable streams: The writable stream is re...