🏋️‍♀️

n8nのノードを作成する ( チュートリアル編 )

2023/08/30に公開

TL;DR

2023年8月現在 n8n公式サイトで公開されているノードを自作してn8nに追加するチュートリアルをなぞった記事です。

ノード作成チュートリアル

公式サイトにアクセスする

https://docs.n8n.io/integrations/creating-nodes/

Prerequisitesにある環境構築を行ってください。

GitHubのリポジトリを作成

作成したリポジトリからclone

ここでは、チュートリアル通りに「nasa-pics」とします。

git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-nasa-pics
cd n8n-nodes-nasa-pics
code .

Visual Studio Codeで確認

不要なファイルやフォルダを削除

以下のファイルやフォルダを削除します。

  • nodes/ExampleNode
  • nodes/HTTPBin
  • credentials/ExampleCredentials.credentials.ts
  • credentials/HttpBinApi.credentials.ts

新規ノード用のファイルやフォルダを作成

以下のファイルやフォルダを作成します。

  • nodes/NasaPics
  • nodes/NasaPics/NasaPics.node.json
  • nodes/NasaPics/NasaPics.node.ts
  • credentials/NasaPicsApi.credentials.ts

プロジェクトに依存するパッケージをインストール

n8n-nodes-nasa-pics> npm i

アイコン画像の保存

こちらからSVGファイルをnodes/NasaPics/nasapics.svgに保存する。

NasaPics.node.tsの実装

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

export class NasaPics implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'NASA Pics',
        name: 'NasaPics',
        icon: 'file:nasapics.svg',
        group: ['transform'],
        version: 1,
        subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
        description: 'Get data from NASAs API',
        defaults: {
        	name: 'NASA Pics',
        },
        inputs: ['main'],
        outputs: ['main'],
        credentials: [
        	{
        		name: 'NasaPicsApi',
        		required: true,
        	},
        ],
        requestDefaults: {
        	baseURL: 'https://api.nasa.gov',
        	headers: {
        		Accept: 'application/json',
        		'Content-Type': 'application/json',
        	},
        },
        properties: [
        	{
        		displayName: 'Resource',
        		name: 'resource',
        		type: 'options',
        		noDataExpression: true,
        		options: [
        			{
        				name: 'Astronomy Picture of the Day',
        				value: 'astronomyPictureOfTheDay',
        			},
        			{
        				name: 'Mars Rover Photos',
        				value: 'marsRoverPhotos',
        			},
        		],
        		default: 'astronomyPictureOfTheDay',
        	},
        	{
                displayName: 'Operation',
                name: 'operation',
                type: 'options',
                noDataExpression: true,
                displayOptions: {
                    show: {
                        resource: [
                            'astronomyPictureOfTheDay',
                        ],
                    },
                },
                options: [
                    {
                        name: 'Get',
                        value: 'get',
                        action: 'Get the APOD',
                        description: 'Get the Astronomy Picture of the day',
                        routing: {
                            request: {
                                method: 'GET',
                                url: '/planetary/apod',
                            },
                        },
                    },
                ],
                default: 'get',
            },
            {
                displayName: 'Operation',
                name: 'operation',
                type: 'options',
                noDataExpression: true,
                displayOptions: {
                    show: {
                        resource: [
                            'marsRoverPhotos',
                        ],
                    },
                },
                options: [
                    {
                        name: 'Get',
                        value: 'get',
                        action: 'Get Mars Rover photos',
                        description: 'Get photos from the Mars Rover',
                        routing: {
                            request: {
                                method: 'GET',
                            },
                        },
                    },
                ],
                default: 'get',
            },
            {
                displayName: 'Rover name',
                description: 'Choose which Mars Rover to get a photo from',
                required: true,
                name: 'roverName',
                type: 'options',
                options: [
                    {name: 'Curiosity', value: 'curiosity'},
                    {name: 'Opportunity', value: 'opportunity'},
                    {name: 'Perseverance', value: 'perseverance'},
                    {name: 'Spirit', value: 'spirit'},
                ],
                routing: {
                    request: {
                        url: '=/mars-photos/api/v1/rovers/{{$value}}/photos',
                    },
                },
                default: 'curiosity',
                displayOptions: {
                    show: {
                        resource: [
                            'marsRoverPhotos',
                        ],
                    },
                },
            },
            {
                displayName: 'Date',
                description: 'Earth date',
                required: true,
                name: 'marsRoverDate',
                type: 'dateTime',
                default:'',
                displayOptions: {
                    show: {
                        resource: [
                            'marsRoverPhotos',
                        ],
                    },
                },
                routing: {
                    request: {
                        // You've already set up the URL. qs appends the value of the field as a query string
                        qs: {
                            earth_date: '={{ new Date($value).toISOString().substr(0,10) }}',
                        },
                    },
                },
            },
            {
                displayName: 'Additional Fields',
                name: 'additionalFields',
                type: 'collection',
                default: {},
                placeholder: 'Add Field',
                displayOptions: {
                    show: {
                        resource: [
                            'astronomyPictureOfTheDay',
                        ],
                        operation: [
                            'get',
                        ],
                    },
                },
                options: [
                    {
                        displayName: 'Date',
                        name: 'apodDate',
                        type: 'dateTime',
                        default: '',
                        routing: {
                            request: {
                                // You've already set up the URL. qs appends the value of the field as a query string
                                qs: {
                                    date: '={{ new Date($value).toISOString().substr(0,10) }}',
                                },
                            },
                        },
                    },
                ],									
            }
        ]
	};
}

nasaPicsApi.credentials.tsの実装

import {
	IAuthenticateGeneric,
	ICredentialType,
	INodeProperties,
} from 'n8n-workflow';

export class NasaPicsApi implements ICredentialType {
	name = 'NasaPicsApi';
	displayName = 'NASA Pics API';
	// Uses the link to this tutorial as an example
	// Replace with your own docs links when building your own nodes
	documentationUrl = 'https://docs.n8n.io/integrations/creating-nodes/build/declarative-style-node/';
	properties: INodeProperties[] = [
		{
			displayName: 'API Key',
			name: 'apiKey',
			type: 'string',
			default: '',
		},
	];
	authenticate = {
		type: 'generic',
		properties: {
			qs: {
				'api_key': '={{$credentials.apiKey}}'
			}
		},
	} as IAuthenticateGeneric;
}

NasaPics.node.jsonの実装

{
	"node": "n8n-nodes-base.NasaPics",
	"nodeVersion": "1.0",
	"codexVersion": "1.0",
	"categories": [
		"Miscellaneous"
	],
	"resources": {
		"credentialDocumentation": [
			{
				"url": ""
			}
		],
		"primaryDocumentation": [
			{
				"url": ""
			}
		]
	}
}

package.jsonの編集

{
	"name": "n8n-nodes-nasapics",
	"version": "0.1.0",
	"description": "n8n node to call NASA's APOD and Mars Rover Photo services.",
	"keywords": [
		"n8n-community-node-package"
	],
	"license": "MIT",
	"homepage": "https://n8n.io",
	"author": {
		"name": "Test",
		"email": "test@example.com"
	},
	"repository": {
		"type": "git",
		"url": "git@github.com:****/****.git"
	},
  "main": "index.js",
  "scripts": {
    "build": "tsc && gulp build:icons",
    "dev": "tsc --watch",
    "format": "prettier nodes credentials --write",
    "lint": "eslint nodes credentials package.json",
    "lintfix": "eslint nodes credentials package.json --fix",
    "prepublishOnly": "npm run build && npm run lint -c .eslintrc.prepublish.js nodes credentials package.json"
  },
  "files": [
    "dist"
  ],
	"n8n": {
		"n8nNodesApiVersion": 1,
		"credentials": [
			"dist/credentials/NasaPicsApi.credentials.js"
		],
		"nodes": [
			"dist/nodes/NasaPics/NasaPics.node.js"
		]
	},
  "devDependencies": {
    "@types/express": "^4.17.6",
    "@types/request-promise-native": "~1.0.15",
    "@typescript-eslint/parser": "~5.45",
    "eslint-plugin-n8n-nodes-base": "^1.11.0",
    "gulp": "^4.0.2",
    "n8n-core": "*",
    "n8n-workflow": "*",
    "prettier": "^2.7.1",
    "typescript": "~4.8.4"
  }
}

n8nのインストール

n8n-nodes-nasa-pics> npm install n8n -g

作成ノードのビルド

n8n-nodes-nasa-pics> npm run build
n8n-nodes-nasa-pics> npm link

local n8nに作成ノードをインストール

n8n-nodes-nasa-pics> cd C:\Users\{your windows user name}\.n8n
C:\Users\****\.n8n > cd nodes
C:\Users\****\.n8n\nodes > npm link n8n-nodes-nasapics

n8nの起動

n8n-nodes-nasa-pics> n8n start

n8n ready on 0.0.0.0, port 5678
Initializing n8n process
Version: 1.4.1

Editor is now accessible via:
http://localhost:5678/

Press "o" to open in Browser.

作成ノードの確認

以上で、公開されているチュートリアルのデプロイ手前までは完了です。

Discussion