Julio Sampaio Software Developer, with an affinity and curiosity for everything else. 🤔💡

First steps with Koa.js

7 min read 2042

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.

We made a custom demo for .
No really. Click here to check it out.

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 compressors, and many more. Please, make sure to refer to the official GitHub project for more on these. Good luck!

You come here a lot! We hope you enjoy the LogRocket blog. Could you fill out a survey about what you want us to write about?

    Which of these topics are you most interested in?
    ReactVueAngularNew frameworks
    Do you spend a lot of time reproducing errors in your apps?
    YesNo
    Which, if any, do you think would help you reproduce errors more effectively?
    A solution to see exactly what a user did to trigger an errorProactive monitoring which automatically surfaces issuesHaving a support team triage issues more efficiently
    Thanks! Interested to hear how LogRocket can improve your bug fixing processes? Leave your email:

    Are you adding new JS libraries to improve performance or build new features? What if they’re doing the opposite?

    There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.

    LogRocket is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.

    https://logrocket.com/signup/

    LogRocket works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.

    Build confidently — .

    Julio Sampaio Software Developer, with an affinity and curiosity for everything else. 🤔💡

    Leave a Reply