Creating a Modular Koa Application

Published Sep 30, 2017
Creating a Modular Koa Application

Introduction

Koa is quite new in Node framework scene. If you have ever worked on Express and have gotten tired of the callback hell when the application gets larger, you will love Koa. It is developed by the same guys behind Express. One of the cool things in Koa is cascading - the middlewares you add will be running 'downstream', then flowing back 'upstream', and that gives you more predictable controls.

The problem

Koa is very minimal and flexible. However, unlike Express which comes with a robust router, Koa by default does not have one. This is a major problem working with Koa as you need to choose a third party package or pick one of packages listed under thier GitHub. You may test out a few and find out they don't work as what you want. This also rises a concern as it lacks of a standard. Probably it is the price for being minimalistic.

After hours of struggling, I finally narrowed it down to combining these two packages that will work almost similar to Express's - koa-mount and koa-trie-router.

Getting started

For how to get started with Koa, there are plenty tutorials available out there (even though many of them were based on the version prior to Koa 2). This article shows you how you can separate the application routes to create a modular directory structure for your application, for an example:

-------------
modules/
    home/
        controllers/
        models/
        views/
    blog/
        controllers/
        models/
        views/
    news/
        controllers/
        models/
        views/
-------------

These are directories and files that I have in my user module:

-------------
_routes/
    delete-user.js
    fetch-user.js
    index.js
    insert-user.js
    update-user.js

controllers/
    delete-user.js
    fetch-user.js
    index.js
    insert-user.js
    update-user.js

models/
    schemas.js
    user.js

index.js <-- the user main route
-------------

Inside the main index.js in user module, I call an instance of koa-trie-router and import all the routes that belong to user:

'use strict'

import Router from 'koa-trie-router'
import fetchUsers from './_routes'
import fetchUser from './_routes/fetch-user'
import insertUser from './_routes/insert-user'
import updateUser from './_routes/update-user'
import deleleUser from './_routes/delete-user'

const router = new Router()

export default () => {
  router.get(fetchUsers())
  router.get(fetchUser())
  router.post(insertUser())
  router.put(updateUser())
  router.del(deleleUser())
  return router.middleware()
}

And then in the application route, I import the user main route in a file called routers.js, alongside with other main routes from other modules:

//routers.js
'use strict'

import Router from 'koa-trie-router'
import mount from 'koa-mount'

// Import routes from different modules.
import home from 'default/home'
import user from 'default/user'

const router = new Router()

export default () => {
  // Add Routes.
  router.use(mount('/', home()))
  router.use(mount('/users', user()))
  return router.middleware()
}

Lastly, I import this routers.js as a middleware in middlewares.js:

// middlewares.js
import mount from 'koa-mount'
import routes from './routes'
...
...
...

app.use(mount('/api', routes()))

You can clone or download this basic modular example from the GitHub repository.

Using the application

To use this application, firstly you need to have Mongo already installed in your machine.

If you have Mongo ready, then install the Node packages:

$ npm install

To serve the app at localhost:3000 (for development):

$ npm run dev

Or (for production):

$ npm start

To test:

$ npm run test

After that you can access these HTTP methods below:

1. The GET method

When you visit the app at http://127.0.0.1:3000, you get:

{"status":404,"message":"Not Found"}

This is because there is not module set for this route /, the application main route starts at api/:

app.use(mount('/api', routes()))

So if you visit it at http://127.0.0.1:3000/api, you get:

{"status":200,"data":{"message":"Hello World!"}}

To vist the user index page, use http://127.0.0.1:3000/api/users, then you get:

{"status":200,"data":[]}

Note that the data is empty - "data":[], this is because there is no user added to the user collection in the database yet.

2. The POST method

Now if you go to Google Postman, create the key below and type in the value in the Body section:

Key     Value
--------------------
name    rob

Choose POST method and hit the Send button, you get:

{
    "status": 200,
    "data": {
        "result": {
            "ok": 1,
            "n": 1
        },
        "ops": [
            {
                "uuid": "ede050e0-9b1c-11e7-a766-4f8befaf2db7",
                "name": "rob",
                "_id": "59bd884d64fa675e298079e0"
            }
        ],
        "insertedCount": 1,
        "insertedIds": [
            "59bd884d64fa675e298079e0"
        ]
    }
}

When you visit http://127.0.0.1:3000/api/users again, you get:

{"status":200,"data":[{"_id":"59bd884d64fa675e298079e0","uuid":"ede050e0-9b1c-11e7-a766-4f8befaf2db7","name":"rob"}]}

You can add more users in and when you just want to query a single user, e.g. http://127.0.0.1:3000/api/users/rob, you get:

{"status":200,"data":{"_id":"59bd884d64fa675e298079e0","uuid":"ede050e0-9b1c-11e7-a766-4f8befaf2db7","name":"rob"}}

3. The PUT method

To update that user, just add the _id key to Postman:

Key     Value
--------------------
name    robbie
_id     59bd884d64fa675e298079e0

When you hit the Send button with the PUT method, you get:

{
    "status": 200,
    "data": {
        "lastErrorObject": {
            "updatedExisting": true,
            "n": 1
        },
        "value": {
            "_id": "59bd884d64fa675e298079e0",
            "uuid": "ede050e0-9b1c-11e7-a766-4f8befaf2db7",
            "name": "robbie"
        },
        "ok": 1
    }
}

4. The DELETE method

Lastly, to delete this user, you just need to provide the _id key in Postman:

Key     Value
--------------------
_id     59bd884d64fa675e298079e0

When you hit the Send button with the DELETE method, it results:

{
    "status": 200,
    "data": {
        "ok": 1,
        "n": 1
    }
}

Conclusion

As you can see it is quite a breeze to develop applications with Koa, and making them modular is possible, once you have the route set up already. Let me know what you think and what router package you use for your projects. Any suggestions and insights, please leave a comment below. Hope this basic example is helpful if you are struggling with the same problem I had.

Discover and read more posts from LAU TIAM KOK
get started
Enjoy this post?

Leave a like and comment for LAU

1