はじめに
n8nというワークフローのサービスがあるのですが、日本ではほとんど話題になっていません。SaaSもあるけど、自分で建てることもできて、それだと月数百円でできるので、是非広まってほしい。自分で建てる方法は下記をご覧ください。
ちなみに、Qiitaで大変バズっていた『しらせ君』、これはn8nで動いていると書かれています。
わたしも真似をして、Slackの通知ボット『Tsutchy』を作り、かなり活躍しています。
本題
n8nでは、Notionからデータを取得したり、Google Driveにファイルを格納したり、Xでツイートしたり、APIさえ公開されていれば、いろいろなことができます。でもその組み合わせだけだとあまり問題解決には至らず、途中で加工します。
単純なところだと、Notionから取得した情報をもとにツイートする文面を作るとか、AというデータソースとBというデータソースを合わせて何かするとか、まぁ切りがないわけですが。
そういう痒い所には、JavaScriptを書くモジュールがあります。これはエンジニアにとっては結構大きいです。(Pythonでも書けます)
ループさせたいとか、フィルタしたいとか、Group Byしたいとか思っても、それ用のモジュールの入力方法がわからないとかできない、ストレスがたまるサービスもあるのです。外部のJavaScriptを実行するサービスに登録して、それを呼び出すとか。まどろっこしすぎる!
そんな便利なn8nですが、課題があって、今回の記事。デバッグしづらい問題。
JavaScriptのモジュールで、コードを書く欄は👇この画面。大きな入力欄があるだけです。
公式掲示板でもデバッグはどうやるのって話題に出ていて、console.log()
しかないよ😭という会話がありました。
そうは言ってもそれはちょっと・・・ということで
解決案:VSCodeで書く
普通ー・・・。すみません。
メリットは3つあります。
1️⃣ テストコードをしっかり書いて、実行しておくことで、インプットとアウトプットの想定が可視化されます。
2️⃣ n8nでは、前のワークフローを何度も実行できないことがあるのですが、外でテストができれば、何度も実行できます。何度も実行できないとは、例えばXへポストし、コードでその結果を使うとか。
3️⃣ 細かく関数化することで、細かくテストできます。
メイン処理を関数化
Codeモジュールの大きな入力欄1つに対して、1つのファイル・1つの関数で定義して、jestでその関数をテストするだけです。はい、普通。
ちょっとした工夫としては、関数にするっていうことくらいでしょうか。
// 新しいフィールドを作って1を設定する
function code1() {
for (const item of $input.all()) {
item.json.myNewField = 1;
}
return $input.all();
}
// return oneCode();
こんな感じで、Code1.js
は関数定義で、テスト後、それをn8nへコピペすればOK。
VSCodeならテスト💯もできるし、デバッグ🪲もできる。
$オブジェクトの定義💰
n8nでは、$オブジェクト(jQueryではありません)で、ワークフローの前に実行した結果を参照できます。$('node1').all()
で、node1
の結果配列要素を取得。
デフォルトで入っている$input
は、直前の処理のアウトプットだと思いますが、順序を入れ替えたりすると"直前の処理"というのが変わって嫌なので、$('node1')
とノード名を指定するようにしています。
コード内では、それを書くので、テスト用に作りました。👇
私は、今のところ$('~~').all()
と$('~~').first()
しか使わないので
/*
n8nのcodeモジュールで使用する"$"関数をモック
*/
const mockResults = {};
const $ = function (nodeName) {
return {
// 前処理の結果データを登録する
registerMockData: (objectArray) => {
console.assert(
Array.isArray(objectArray),
'objectArray must be an array'
);
mockResults[nodeName] = objectArray.map((obj) => ({json: obj}));
},
// n8nで使用する関数
all: () => mockResults[nodeName],
first: () => mockResults[nodeName][0],
};
};
module.exports = $;
これをテストで使うときには、👇こんな感じで。
const $ = require('../n8n_object');
const code1 = require('../code1');
describe('code1', () => {
it('code1_simple_test1', () => {
// テストデータの準備
$('node0').registerMockData([
{
id: 1,
val: "abc",
},
{
id: 2,
val: "def",
},
]);
// 実行
result = code1();
// 検証
expect(result.length).toBe(2);
expect(result[0].id).toBe(1);
expect(result[0].val).toBe("abc");
expect(result[0].myNewField).toBe(1);
expect(result[1].id).toBe(2);
expect(result[1].val).toBe("def");
expect(result[1].myNewField).toBe(2);
});
});
jestのテストケースを、VSCodeのデバッグ実行ができるので、デバッグもできます。この設定は「vscode jest デバッグ」あたりでググれば出てきます。
おわりに
n8nはとても便利なのですが、コーディングがメインではないので、手厚くはないです。なので自前で外に環境を作って、外でテストをして、n8nへ移行するという形でした。
Qiitaを見てn8nを使うような人は、Codeモジュールは必ず使うと思います。これを作っておくことで安心感・安定感が増すので、n8nを使う人はやってみてください。
ではよきワークフローライフを!