/koa-es7-boilerplate

A boilerplate for writing Koa 2 apps in ES7 with Babel.

Primary LanguageJavaScriptMIT LicenseMIT

Koa Boilerplate

KoaJs Slack

✨ A boilerplate for writing beautiful async-await-based Koa API's using babel for Node v8.0 and above!. 🚀

Setting up shop

Clone this repo and adjust details in package.json. Remove the .git directory and git init to start fresh.

Read on to learn how to actually start being productive.

What's in the package?

  • 🏃‍♀️   npm run scripts, see next section for details.
  • 🛣   awilix-koa for declarative routing.
  • 🗣   babel with env presets, transform-runtime + transform-object-rest-spread plugins and sourcemaps.
  • 🃏   jest for testing with some API testing helpers.
  • 💪   koa-bodyparser for parsing request bodies.
  • ✅   eslint with standard, works with ES7 thanks to babel-eslint.
  • 👀   prettier code formatting, configured to work with eslint out of the box.
  • 🐶   husky + lint-staged to lint and format files when committing.
  • ❌   @koa/cors CORS middleware for cross-domain requests.
  • 🕵️‍♀️   nodemon for development to auto-restart when your files change.
  • 🛠   koa-respond for helper functions on the context.
  • 📄    yenv for environment variable management.
  • 💉    awilix for dependency injection / IoC.
  • ⚠️    fejl for assertions and errors.

npm run scripts

There are a few defined run scripts, here's a list of them with a description of what they do. To run them, simply execute npm run <script name> - e.g. npm run dev

  • start: Used by the production environment to start the app. This will run a compiled version, so you need to execute build first.
  • build: Runs the babel CLI to compile the app. Files are emitted to dist/.
  • dev: Runs the app in development mode - uses babel-node to compile on-the-fly. Also uses nodemon to automatically restart when stuff changes.
  • test: Runs tests.
  • cover: Runs tests and collects coverage.
  • lint: Lints + formats the code.

Tip: to pass additional arguments to the actual CLI's being called, do it like in this example:

For npm:

# Note the `--` before the actual arguments.
npm run test -- --debug

For yarn:

# Yarn does not need the `--` before the actual arguments.
yarn test --debug

docker-compose up scripts

For running dev:

# Note: use --build only when you want to build. Usually when you change packages.json
docker-compose up --build

For running test:

docker-compose -f docker-compose.test.yml up

Directory structure

The repository root contains auxiliary files like package.json, .gitignore, etc.

  • src: the actual source for the app goes here. Duh.
    • __tests__: In the source root folder, contains integration tests.
    • routes: API endpoints go here, and are automatically loaded at startup. Please see the section about API endpoints for details.
    • bin: files that are usually executed by npm run scripts, e.g. starting the server.
    • lib: stuff that helps the app start up, e.g. environment, logger, the container configuration, etc.
    • middleware: custom app middleware.
    • services: application services, this is just to illustrate the dynamic discovery of stuff as described in the Dependency injection section.
      • __tests__: Unit tests for files in the services directory.
    • [your directory]: you can plop anything else here, too.
      • __tests__: Unit tests for files in your directory.

Testing

To recap the previous section, src/__tests__ are for integration tests, and any __tests__ folder under src/<folder> are unit tests.

Test files must end with .test.js.

There is a src/__tests__/api-helper.js that makes writing integration tests way easier. Simply replace the example functions with ones matching your own API. The created server instance is closed whenever all tests are done as to not leak resources. This is why it's important to close network connections in the close event!

Environment variables

The environment variables can be reached by importing lib/env.

import { env } from '../lib/env'

Additionally, all environment variables you'd usually find on process.env will be available on this object.

When attempting to access a key (env.PORT for example), if the key does not exist an error is thrown and the process terminated.

In the repository root, you will find a env.yaml, which is where you can set up environment variables so you won't have to do it from your shell. This also makes it more platform-agnostic.

The top-level nodes in the YAML-file contain a set of environment variables. yenv will load the set that matches whatever NODE_ENV says.

I've set it up so anything in tests will override anything in development when running tests.

Actual environment variables will take precedence over the env.yaml file!

See the yenv docs for more info.

API endpoints

Each file in /routes exports a "controller" that awilix-koa will use for routing. Please see awilix-koa docs for more information.

Dependency injection

This boilerplate uses the Awilix container for managing dependencies - please check out the Awilix documentation for details. The container is configured in lib/container.js.

Middleware

Middleware is located in the middleware folder and is not automatically loaded - they should be installed in lib/server.

Author

License

MIT.