n8n.ioでプリザンターのノードを自作してAPI連携してみた！

## 概要
プリザンターは、API機能を使用して他システムとデータの入出力を行うことが可能です。本記事ではOSSのワークフロー作成ツールであるn8n.ioでプリザンターのノードを作成し、API連携を行う方法について説明します。

## n8n.ioを動かしてみる

まずはn8n.ioがどんなものかを知るために次の手順で動かしてみましょう。

### 事前準備

プリザンターのノードを作成するために、Node.jsをインストールしてください。

https://nodejs.org/ja/

※n8n.ioのDocsにてNode.jsのバージョンは14.xを使用するよう注意書きがあり、2021年12月4日時点で推奨版のNode.js（16.13.1 LTS）ではノード作成のビルド時にエラーが発生しました。動作確認を行ったバージョンは以下のとおりです。

Node.js：v14.17.4
npm：6.14.14

### n8n.ioの起動確認

https://n8n.io/

楽しそうな画面が現れました。「Get started」ボタンをクリックして画面下部に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/d5320b72-3686-7c23-dcb7-54353eed9054.png)

ここでは、npmコマンドが使えることを確認するために右側の「Self-host」を選んでみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/dadfadc2-494a-6341-9b1e-8582e0976f6b.png)

※n8n.ioはつい最近デスクトップ版がリリースされたようです。（リリース発表の公式ブログ日付は2021年11月4日となっていました。）お手軽に試してみたい人はデスクトップ版をダウンロードしてみてください。無料で使えるのがすごいですね！

npmコマンドでn8nをインストールします。

```cmd:n8nのインストール
npm install n8n -g
```

```cmd:n8n.ioを起動
cd .n8n  // Windowsの場合はn8nを実行する前にホームフォルダへの移動が必要
n8n
```

実行すると、コンソールに「Editor is now accessible」のメッセージが表示されるので、http://localhost:5678/workflow に接続してみます。コンソール上で"o"のキーを押せばブラウザが自動的に立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/befffba7-319f-db01-d96e-928ac5fdff31.png)

起動できました！簡単ですね。

## プリザンターのノード作成

HTTP Requestノードを使ってワークフローを作成する方法もあるのですが、わかりやすいUIを目指して今回はプリザンターのノードを作成する方法を試してみます。

### ノードの作成

まずはn8n.ioのDocsに従い、次のコマンドを実行して任意の場所にリポジトリをcloneします。

```cmd:バージョン確認
node -v
npm -v
```

```cmd:lernaのインストール
npm install --global lerna
```

```cmd:リポジトリのclone
git clone https://github.com/n8n-io/n8n
```

次の手順でプリザンター用のノードを作成します。

1. 「packages/nodes-base/nodes」に移動します。
1. 「Pleasanter」というフォルダを作成します。
1. 「Pleasanter」フォルダー内に「Pleasanter.node.ts」というファイルを作成します。
1. プリザンターのノードに設定するアイコン用の画像ファイルを「Pleasanter」フォルダー内に「pleasanter.png」というファイル名で追加します。
1. 次のコードを「Pleasanter.node.ts」ファイルに貼り付けます。

```TypeScript:n8n/packages/nodes-base/nodes/Pleasanter/Pleasanter.node.ts
import {
	IExecuteFunctions,
} from 'n8n-core';

import {
	IDataObject,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
} from 'n8n-workflow';

import {
	OptionsWithUri,
} from 'request';

export class Pleasanter implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'Pleasanter',
		name: 'pleasanter',
		icon: 'file:pleasanter.png',
		group: ['transform'],
		version: 1,
		description: 'Consume Pleasanter API',
		defaults: {
			name: 'Pleasanter',
			color: '#f18308',
		},
		inputs: ['main'],
		outputs: ['main'],
		credentials: [
			{
				name: 'pleasanterApi',
				required: true,
			},
		],
		properties: [
			// Node properties which the user gets displayed and
			// can change on the node.
		],
	};
	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		return [[]];
	}
}
```

### エディタUIへのノードの追加
「n8n/packages/nodes-base/package.json」を以下のとおり修正します。

1. n8n.nodes に以下の行を追加します。（アルファベット順）

```cmd:n8n/packages/nodes-base/package.json
      "dist/nodes/Pleasanter/Pleasanter.node.js",
```

### プロパティ情報の設定

ユーザーがノード上で設定できるプロパティ情報を設定します。次のコードはサンプルなので、目的に合わせてカスタマイズしてください。

1. 「packages/nodes-base/nodes/Pleasanter/Pleasanter.node.ts」のdescription.propertiesに次の行を追加します。

```TypeScript:n8n/packages/nodes-base/nodes/Pleasanter/Pleasanter.node.ts
			{
				displayName: 'URL',
				name: 'url',
				type: 'string',
				required: true,
				default: '',
				description: 'Pleasanter URL',
			},
			{
				displayName: 'Controller Name',
				name: 'controllerName',
				type: 'options',
				options: [
					{
						name: 'Items',
						value: 'items',
					},
					{
						name: 'Depts',
						value: 'depts',
					},
					{
						name: 'Groups',
						value: 'groups',
					},
					{
						name: 'Users',
						value: 'users',
					},
					{
						name: 'Binaries',
						value: 'binaries',
					},
				],
				default: 'items',
				required: true,
				description: 'Controller to operate',
			},
			{
				displayName: 'Record Id',
				name: 'recordId',
				type: 'string',
				required: true,
				displayOptions: {
					show: {
						controllerName: [
							'items',
						],
						methodName: [
							'get',
						],
					},
				},
				default: '',
				description: 'Target Record Id',
			},
			{
				displayName: 'Method Name',
				name: 'methodName',
				type: 'options',
				options: [
					{
						name: 'Get',
						value: 'get',
					},
					{
						name: 'Create',
						value: 'create',
					},
					{
						name: 'Update',
						value: 'update',
					},
					{
						name: 'Delete',
						value: 'delete',
					},
				],
				default: 'get',
				description: 'The method to perform.',
			},
```

### クレデンシャル用UIの作成

PleasanterAPIキーを要求するUIを作成するために次のファイルを用意します。

1. 「packages/nodes-base/credentials」に移動します。
1. 「credentials」フォルダー内に「PleasanterApi.credentials.ts」という名前のファイルを作成します。
1. 次のコードを貼り付けます。

```TypeScript:n8n/packages/nodes-base/credentials/PleasanterApi.credentials.ts
import {
	ICredentialType,
	NodePropertyTypes,
} from 'n8n-workflow';

export class PleasanterApi implements ICredentialType {
	name = 'pleasanterApi';
	displayName = 'Pleasanter API';
	documentationUrl = 'pleasanter';
	properties = [
		{
			displayName: 'API Key',
			name: 'apiKey',
			type: 'string' as NodePropertyTypes,
			default: '',
		},
	];
}
```

「n8n/packages/nodes-base/package.json」を以下のとおり修正します。

1. n8n.credentials に以下の行を追加します。（アルファベット順）

```cmd:n8n/packages/nodes-base/package.json
      "dist/credentials/PleasanterApi.credentials.js",
```

### UIフィールドのAPIへのマッピング

ユーザーがUIで設定したパラメーターにアクセスできるようにします。フィールドをAPIにマップするには、次の手順を実行します。こちらもサンプルコードになります。

1. 「package/nodes-base/Pleasanter/Pleasanter.node.ts」に移動します。
1. executeメソッドを次のコードに置き換えます。

```TypeScript:n8n/packages/nodes-base/nodes/Pleasanter/Pleasanter.node.ts
	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		let responseData;
		const controllerName = this.getNodeParameter('controllerName', 0) as string;
		const methodName = this.getNodeParameter('methodName', 0) as string;
		//Get credentials the user provided for this node
		const credentials = await this.getCredentials('pleasanterApi') as IDataObject;

		if (controllerName === 'items') {
			if (methodName === 'get') {
				const url = this.getNodeParameter('url', 0) as string;
				const recordId = this.getNodeParameter('recordId', 0) as string;
				const data: IDataObject = {
					url,
					recordId,
				};

				Object.assign(data);

				//Make http request according to <https://pleasanter.org/manual/api>
				const options: OptionsWithUri = {
					method: 'POST',
					headers: {
						"Content-Type": "application/json",
						"charset": "UTF-8",
					},
					uri: `${url}/api/${controllerName}/${recordId}/${methodName}`,
					body: {
						"ApiVersion": 1.1,
						"ApiKey": `${credentials.apiKey}`,
					},
					json: true,
				};

				responseData = await this.helpers.request(options);
			}
		}

		// Map data to n8n data
		return [this.helpers.returnJsonArray(responseData)];
	}
```

### 開発モードでの起動

ここまでできたらプロジェクトのメインフォルダー（n8n）に移動し、次のコマンドを実行して起動してみましょう。

```cmd:すべてのモジュールの依存関係をインストールしてリンクする
lerna bootstrap --hoist
```
```cmd:すべてのコードをビルド
npm run build
```
```cmd:開発モードでn8nを開始
npm run dev
```

コンソールにカラフルなメッセージが出力されます。出力が完了したらhttp://localhost:8080/workflow に接続してみます。

## ワークフローの作成

### プリザンター側でAPIキーを作成する

プリザンターのマニュアルを参考に、APIキーを作成しておきます。

### n8n.ioでプリザンターのノードを追加する

右側の検索欄で「Pleasanter」と検索して対象を選択することで、ワークフロー上にPleasanterのノードが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/bcc6429c-deb2-477c-3924-2a2fb38016ea.png)

### ノードを実行する

プリザンターのノードを選択してParametersに必要な情報を入力します。先ほど設定したプロパティ情報が選択肢に表示されていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/3de737d9-5426-7798-b632-c383ed669dc1.png)

「Credential for Pleasanter API」には先ほどプリザンター側で作成したAPIキーを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/ad107c75-f587-739f-6632-6515cb19a98f.png)

そして、右上の「Execute Node」ボタンをクリックすると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37295/7f515f46-fe57-fa3a-9090-6ee4ee7dcb44.png)

プリザンターのレコード情報をJSON形式で取得することができました！

これをベースにしてプリザンターのノードから例えばチャットツールなど、別のアプリのノードに接続して通知させるといったことができそうですね。

今回は単一レコードの取得について試してみましたが、逆にn8n.ioからプリザンターへのレコード作成や更新もできるはずなので、興味のある方はチャレンジしてみてください。

## おわりに

プリザンターはAPIの機能により他システムと連携することができます。最近ではExcelとの連携も盛り上がってきているようです。ますます発展するプリザンターの今後に目が離せませんね！

## 参考リンク

[- Pleasanterユーザマニュアル - 開発者向け機能：API](https://pleasanter.org/manual/api)
[- Pleasanterユーザマニュアル - 開発者向け機能：API：APIキーの作成](https://pleasanter.org/manual/api-key)
[- Pleasanterユーザマニュアル - 開発者向け機能：API：APIのURL](https://pleasanter.org/manual/api-url)
[- Pleasanterユーザマニュアル - 開発者向け機能：API：テーブル操作：単一レコード取得](https://pleasanter.org/manual/api-record-get)
[- n8n.io Docs - Getting Started- Installation - Self-hosting n8n](https://docs.n8n.io/getting-started/installation/#self-hosting-n8n)
[- n8n.io Docs - Nodes- Creating Node - Creating Your First Node](https://docs.n8n.io/nodes/creating-nodes/create-node.html)
[- Torimemo - n8n.io ノードを作る(マニュアル)](https://torimemoblog.wordpress.com/2020/01/17/n8n-io-%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB/)