LoginSignup
19
10

More than 5 years have passed since last update.

nodejs, ES6 で dependency injection with awilix

Last updated at Posted at 2017-07-28

概要

nodejs でちょっとしたアプリ(WebAPI や DB からデータを取得して、AWS S3に登録する)を作ることになりました。
小さなコードなので、typescript とか使うのも面倒だなと思い、ES6 で書いていました。
プロトタイプ的に一通り実装したあと、プロダクト用に仕上げるに当たって、やはり DI 必要だなと思い、調べていたところ、awilix が使いやすかったという話です。

そもそも何で DI が必要か

プロトタイプでは DAO を以下のように実装していました。

dao.js
const webDAO = require("./net"); // WEB API 通信モジュール
const dbDAO = require("./db"); // DB 操作モジュール
const s3 = require("./s3"); // S3 操作モジュール

module.exports = {
    getData1: function(code){
        return webDAO.getData(code);
    },
    getData2: function(type){
        return dbDAO.getData(type);
    },
    putData: function(key, data){
        return s3.putObject(key, data);
    }
};

使う側は以下のような感じです。

userSide.js
const dao = require("./dao");

const data1 = dao.getData1("sample");
dao.putData("sampleKey", data1);

で、これだと困ることがいくつかあります。

  • ローカル環境では S3 じゃなくてファイルに出力したいこともある
  • ローカル環境ではデータを固定にしたいこともある
  • 一連の処理のテストコードを書きたいが、外部リソースに依存していては・・・

と言うわけで DI の出番です。

Awilix が良いと思った理由

JS の DI framework って決定版的なものがないですよね、きっと。
以前に typescript を使った時は inversifyJS を使ったのですが、JS対応はイマイチだったので、他を探していたところ、Awilixを見つけました。

シンプルで使い勝手が良さそうです。ES6 の Proxy を使っているらしいです。

DI 版に修正する

※サンプルなので諸々テキトーです。

DI なので dao をコンストラクタで受け取るようにします。

const awilix = require('awilix');

const container = awilix.createContainer();

// モックの DAO
function mock() {
    const fs = require("fs-extra");
    container.registerValue({
        dao: {
            getData1: function(code){
                return [];
            },
            getData2: function(type){
                return [];
            },
            putData: function(key, data){
                return fs.outputFile(`${key}.txt`, data);
            }
        }
    });
}

// プロダクト用の DAO
function prod() {
    const dao = require("./dao/dao");
    container.registerValue({dao: dao});
}

mock(); // 注:ここを環境によって切り替える。
// prod();


// 以下、使う側

class TestUser {
    constructor(opts) {
        this.dao = opts.dao; // モックまたはプロダクト用の DAO がインジェクトされる
    }

    test() {
        this.dao.getData1("sample");
    }
}

container.registerClass({
    testUser: TestUser
});

const testUser = container.resolve("testUser");
testUser.test();

サンプルなので諸々テキトーです。
Usageが分かりやすいので、そちらを参照してください。

まとめ

Awilix で testable な nodejs 開発をしましょー。

19
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
10