Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

nodejs, ES6 で dependency injection with awilix

概要

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 開発をしましょー。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
10
Help us understand the problem. What are the problem?