Skip to content

构建程序化风格的节点#

¥Build a programmatic-style node

本教程将逐步讲解如何构建程序式节点。开始前,请确保这是你需要的节点样式。有关更多信息,请参阅 选择你的节点构建方法

¥This tutorial walks through building a programmatic-style node. Before you begin, make sure this is the node style you need. Refer to Choose your node building approach for more information.

先决条件#

¥Prerequisites

你的开发机器上需要安装以下软件:

¥You need the following installed on your development machine:

  • git
  • Node.js and npm. Minimum version Node 18.17.0. You can find instructions on how to install both using nvm (Node Version Manager) for Linux, Mac, and WSL here. For Windows users, refer to Microsoft's guide to Install NodeJS on Windows.

你需要了解以下内容:

¥You need some understanding of:

  • JavaScript/TypeScript

  • REST API

  • git

  • n8n 中的 表达式

¥Expressions in n8n

构建节点#

¥Build your node

在本部分中,你将克隆 n8n 的节点入门存储库,并构建一个集成 SendGrid 的节点。你将创建一个节点来实现 SendGrid 的一项功能:创建联系人。

¥In this section, you'll clone n8n's node starter repository, and build a node that integrates the SendGrid. You'll create a node that implements one piece of SendGrid functionality: create a contact.

Existing node

n8n 内置了 SendGrid 节点。为避免与现有节点冲突,你需要为版本指定一个不同的名称。

¥n8n has a built-in SendGrid node. To avoid clashing with the existing node, you'll give your version a different name.

步骤 1:设置项目#

¥Step 1: Set up the project

n8n 提供了一个用于节点开发的入门仓库。使用启动器可确保你拥有所有必要的依赖。还提供了一个代码检查器。

¥n8n provides a starter repository for node development. Using the starter ensures you have all necessary dependencies. It also provides a linter.

克隆存储库并导航到目录:

¥Clone the repository and navigate into the directory:

  1. 模板存储库,请参阅 生成新存储库

¥Generate a new repository from the template repository. 2. 克隆新存储库:shell git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-friendgrid cd n8n-nodes-friendgrid

¥Clone your new repository: shell git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-friendgrid cd n8n-nodes-friendgrid

入门套件包含示例节点和凭据。删除以下目录和文件:

¥The starter contains example nodes and credentials. Delete the following directories and files:

  • nodes/ExampleNode

  • nodes/HTTPBin

  • credentials/ExampleCredentials.credentials.ts

  • credentials/HttpBinApi.credentials.ts

现在创建以下目录和文件:

¥Now create the following directories and files:

nodes/FriendGrid nodes/FriendGrid/FriendGrid.node.json nodes/FriendGrid/FriendGrid.node.ts credentials/FriendGridApi.credentials.ts

这些是任何节点都需要的关键文件。有关所需文件和推荐组织方式的更多信息,请参阅 节点文件结构

¥These are the key files required for any node. Refer to Node file structure for more information on required files and recommended organization.

现在安装项目依赖:

¥Now install the project dependencies:

1
npm i

步骤 2:添加图标#

¥Step 2: Add an icon

此处 中的 SendGrid SVG 徽标保存为 nodes/FriendGrid/ 中的 friendGrid.svg

¥Save the SendGrid SVG logo from here as friendGrid.svg in nodes/FriendGrid/.

n8n recommends using an SVG for your node icon, but you can also use PNG. If using PNG, the icon resolution should be 60x60px. Node icons should have a square or near-square aspect ratio.

Don't reference Font Awesome

If you want to use a Font Awesome icon in your node, download and embed the image.

步骤 3:在基础文件中定义节点#

¥Step 3: Define the node in the base file

每个节点都必须有一个基础文件。有关基础文件参数的详细信息,请联系 节点基础文件

¥Every node must have a base file. Refer to Node base file for detailed information about base file parameters.

本示例中,文件为 FriendGrid.node.ts。为了保持本教程简洁,你需要将所有节点功能放在一个文件中。构建更复杂的节点时,你应该考虑将功能拆分为模块。有关更多信息,请参阅 节点文件结构

¥In this example, the file is FriendGrid.node.ts. To keep this tutorial short, you'll place all the node functionality in this one file. When building more complex nodes, you should consider splitting out your functionality into modules. Refer to Node file structure for more information.

步骤 3.1:导入#

¥Step 3.1: Imports

首先添加导入语句:

¥Start by adding the import statements:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import {
	IExecuteFunctions,
} from 'n8n-core';

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

import {
	OptionsWithUri,
} from 'request';

步骤 3.2:创建主类#

¥Step 3.2: Create the main class

该节点必须导出实现 INodeType 接口的接口。此接口必须包含一个 description 接口,该接口又包含 properties 数组。

¥The node must export an interface that implements INodeType. This interface must include a description interface, which in turn contains the properties array.

Class names and file names

请确保类名和文件名匹配。例如,给定一个类 FriendGrid,文件名必须为 FriendGrid.node.ts

¥Make sure the class name and the file name match. For example, given a class FriendGrid, the filename must be FriendGrid.node.ts.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export class FriendGrid implements INodeType {
	description: INodeTypeDescription = {
		// Basic node details will go here
		properties: [
			// Resources and operations will go here
		],
	};
	// The execute method will go here
	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
	}
}

步骤 3.3:添加节点详细信息#

¥Step 3.3: Add node details

所有程序化节点都需要一些基本参数,例如其显示名称和图标。将以下内容添加到 description

¥All programmatic nodes need some basic parameters, such as their display name and icon. Add the following to the description:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
displayName: 'FriendGrid',
name: 'friendGrid',
icon: 'file:friendGrid.svg',
group: ['transform'],
version: 1,
description: 'Consume SendGrid API',
defaults: {
	name: 'FriendGrid',
},
inputs: [NodeConnectionType.Main],
outputs: [NodeConnectionType.Main],
credentials: [
	{
		name: 'friendGridApi',
		required: true,
	},
],

n8n 使用 description 中设置的一些属性在编辑器 UI 中渲染节点。这些属性为 displayNameicondescription

¥n8n uses some of the properties set in description to render the node in the Editor UI. These properties are displayName, icon, and description.

步骤 3.4:添加资源#

¥Step 3.4: Add the resource

资源对象定义了节点使用的 API 资源。在本教程中,你将创建一个节点来访问 SendGrid 的一个 API 端点:/v3/marketing/contacts。这意味着你需要为此端点定义一个资源。使用资源对象更新 properties 数组:

¥The resource object defines the API resource that the node uses. In this tutorial, you're creating a node to access one of SendGrid's API endpoints: /v3/marketing/contacts. This means you need to define a resource for this endpoint. Update the properties array with the resource object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
	displayName: 'Resource',
	name: 'resource',
	type: 'options',
	options: [
		{
			name: 'Contact',
			value: 'contact',
		},
	],
	default: 'contact',
	noDataExpression: true,
	required: true,
	description: 'Create a new contact',
},

type 控制 n8n 为资源显示的 UI 元素,并告知 n8n 预期从用户获取的数据类型。options 会导致 n8n 添加一个下拉列表,允许用户选择一个选项。有关更多信息,请参阅 节点 UI 元素

¥type controls which UI element n8n displays for the resource, and tells n8n what type of data to expect from the user. options results in n8n adding a dropdown that allows users to choose one option. Refer to Node UI elements for more information.

步骤 3.5:添加操作#

¥Step 3.5: Add operations

操作对象定义了你可以对资源执行的操作。它通常与 REST API 动词(GET、POST 等)相关。在本教程中,只有一个操作:创建联系人。它有一个必填字段,即用户创建的联系人的电子邮件地址。

¥The operations object defines what you can do with a resource. It usually relates to REST API verbs (GET, POST, and so on). In this tutorial, there's one operation: create a contact. It has one required field, the email address for the contact the user creates.

resource 对象之后,将以下内容添加到 properties 数组:

¥Add the following to the properties array, after the resource object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
	displayName: 'Operation',
	name: 'operation',
	type: 'options',
	displayOptions: {
		show: {
			resource: [
				'contact',
			],
		},
	},
	options: [
		{
			name: 'Create',
			value: 'create',
			description: 'Create a contact',
			action: 'Create a contact',
		},
	],
	default: 'create',
	noDataExpression: true,
},
{
	displayName: 'Email',
	name: 'email',
	type: 'string',
	required: true,
	displayOptions: {
		show: {
			operation: [
				'create',
			],
			resource: [
				'contact',
			],
		},
	},
	default:'',
	placeholder: 'name@email.com',
	description:'Primary email for the contact',
},

步骤 3.6:添加可选字段#

¥Step 3.6: Add optional fields

大多数 API,包括本示例中使用的 SendGrid API,都提供可用于优化查询的可选字段。

¥Most APIs, including the SendGrid API that you're using in this example, have optional fields you can use to refine your query.

为避免信息过载,n8n 会在用户界面中的“附加字段”下显示这些信息。

¥To avoid overwhelming users, n8n displays these under Additional Fields in the UI.

在本教程中,你将添加两个额外的字段,允许用户输入联系人的名字和姓氏。将以下内容添加到 properties 数组:

¥For this tutorial, you'll add two additional fields, to allow users to enter the contact's first name and last name. Add the following to the properties array:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
	displayName: 'Additional Fields',
	name: 'additionalFields',
	type: 'collection',
	placeholder: 'Add Field',
	default: {},
	displayOptions: {
		show: {
			resource: [
				'contact',
			],
			operation: [
				'create',
			],
		},
	},
	options: [
		{
			displayName: 'First Name',
			name: 'firstName',
			type: 'string',
			default: '',
		},
		{
			displayName: 'Last Name',
			name: 'lastName',
			type: 'string',
			default: '',
		},
	],
},

步骤 4:添加 execute 方法#

¥Step 4: Add the execute method

你已设置节点 UI 和基本信息。现在是时候将节点 UI 映射到 API 请求,并让节点实际执行某些操作了。

¥You've set up the node UI and basic information. It's time to map the node UI to API requests, and make the node actually do something.

execute 方法在节点每次运行时都会执行。在此方法中,你可以访问用户在用户界面中设置的输入项和参数,包括凭据。

¥The execute method runs every time the node runs. In this method, you have access to the input items and to the parameters that the user set in the UI, including the credentials.

FriendGrid.node.tsexecute 方法中添加以下内容:

¥Add the following the execute method in the FriendGrid.node.ts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Handle data coming from previous nodes
const items = this.getInputData();
let responseData;
const returnData = [];
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;

// For each item, make an API call to create a contact
for (let i = 0; i < items.length; i++) {
	if (resource === 'contact') {
		if (operation === 'create') {
			// Get email input
			const email = this.getNodeParameter('email', i) as string;
			// Get additional fields input
			const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
			const data: IDataObject = {
				email,
			};

			Object.assign(data, additionalFields);

			// Make HTTP request according to https://sendgrid.com/docs/api-reference/
			const options: OptionsWithUri = {
				headers: {
					'Accept': 'application/json',
				},
				method: 'PUT',
				body: {
					contacts: [
						data,
					],
				},
				uri: `https://api.sendgrid.com/v3/marketing/contacts`,
				json: true,
			};
			responseData = await this.helpers.requestWithAuthentication.call(this, 'friendGridApi', options);
			returnData.push(responseData);
		}
	}
}
// Map data to n8n data structure
return [this.helpers.returnJsonArray(returnData)];

请注意以下代码行:

¥Note the following lines of this code:

1
2
3
4
5
6
7
const items = this.getInputData();
... 
for (let i = 0; i < items.length; i++) {
	...
	const email = this.getNodeParameter('email', i) as string;
	...
}

用户可以通过两种方式提供数据:

¥Users can provide data in two ways:

  • 直接在节点字段中输入

¥Entered directly in the node fields

  • 通过映射工作流中先前节点的数据。

¥By mapping data from earlier nodes in the workflow

getInputData() 及其后续循环允许节点处理数据来自先前节点的情况。这包括支持多个输入。这意味着,例如,如果前一个节点输出五个人的联系信息,则你的 FriendGrid 节点可以创建五个联系人。

¥getInputData(), and the subsequent loop, allows the node to handle situations where data comes from a previous node. This includes supporting multiple inputs. This means that if, for example, the previous node outputs contact information for five people, your FriendGrid node can create five contacts.

步骤 5:设置身份验证#

¥Step 5: Set up authentication

SendGrid API 要求用户使用 API 密钥进行身份验证。

¥The SendGrid API requires users to authenticate with an API key.

将以下内容添加到 FriendGridApi.credentials.ts

¥Add the following to FriendGridApi.credentials.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import {
	IAuthenticateGeneric,
	ICredentialTestRequest,
	ICredentialType,
	INodeProperties,
} from 'n8n-workflow';

export class FriendGridApi implements ICredentialType {
	name = 'friendGridApi';
	displayName = 'FriendGrid API';
	properties: INodeProperties[] = [
		{
			displayName: 'API Key',
			name: 'apiKey',
			type: 'string',
			default: '',
		},
	];

	authenticate: IAuthenticateGeneric = {
		type: 'generic',
		properties: {
			headers: {
				Authorization: '=Bearer {{$credentials.apiKey}}',
			},
		},
	};

	test: ICredentialTestRequest = {
		request: {
			baseURL: 'https://api.sendgrid.com/v3',
			url: '/marketing/contacts',
		},
	};
}

有关凭据文件和选项的更多信息,请参阅 凭据文件

¥For more information about credentials files and options, refer to Credentials file.

步骤 6:添加节点元数据#

¥Step 6: Add node metadata

关于节点的元数据位于节点根目录下的 JSON 文件中。n8n 将此称为 codex 文件。本示例中,文件为 FriendGrid.node.json

¥Metadata about your node goes in the JSON file at the root of your node. n8n refers to this as the codex file. In this example, the file is FriendGrid.node.json.

将以下代码添加到 JSON 文件:

¥Add the following code to the JSON file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
	"node": "n8n-nodes-base.FriendGrid",
	"nodeVersion": "1.0",
	"codexVersion": "1.0",
	"categories": [
		"Miscellaneous"
	],
	"resources": {
		"credentialDocumentation": [
			{
				"url": ""
			}
		],
		"primaryDocumentation": [
			{
				"url": ""
			}
		]
	}
}

有关这些参数的更多信息,请参阅 节点代码库文件

¥For more information on these parameters, refer to Node codex files.

步骤 7:更新 npm 包详细信息#

¥Step 7: Update the npm package details

你的 npm 包详细信息位于项目根目录下的 package.json 文件中。必须包含指向凭据和基础节点文件的链接的 n8n 对象。更新此文件以包含以下信息:

¥Your npm package details are in the package.json at the root of the project. It's essential to include the n8n object with links to the credentials and base node file. Update this file to include the following information:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
	// All node names must start with "n8n-nodes-"
	"name": "n8n-nodes-friendgrid",
	"version": "0.1.0",
	"description": "n8n node to create contacts in SendGrid",
	"keywords": [
		// This keyword is required for community nodes
		"n8n-community-node-package"
	],
	"license": "MIT",
	"homepage": "https://n8n.nodejs.cn",
	"author": {
		"name": "Test",
		"email": "test@example.com"
	},
	"repository": {
		"type": "git",
		// Change the git remote to your own repository
		// Add the new URL here
		"url": "git+<your-repo-url>"
	},
	"main": "index.js",
	"scripts": {
		// don't change
	},
	"files": [
		"dist"
	],
	// Link the credentials and node
	"n8n": {
		"n8nNodesApiVersion": 1,
		"credentials": [
			"dist/credentials/FriendGridApi.credentials.js"
		],
		"nodes": [
			"dist/nodes/FriendGrid/FriendGrid.node.js"
		]
	},
	"devDependencies": {
		// don't change
	},
	"peerDependencies": {
		// don't change
	}
}

你需要更新 package.json 节点以包含你自己的信息,例如你的名称和存储库 URL。有关 npm package.json 文件的更多信息,请参阅 npm package.json 文档

¥You need to update the package.json to include your own information, such as your name and repository URL. For more information on npm package.json files, refer to npm's package.json documentation.

测试你的节点#

¥Test your node

You can test your node as you build it by running it in a local n8n instance.

  1. Install n8n using npm:
    1
    npm install n8n -g
    
  2. When you are ready to test your node, publish it locally:
    1
    2
    3
    # In your node directory
    npm run build
    npm link
    
  3. Install the node into your local n8n instance:

    1
    2
    3
    # In the nodes directory within your n8n installation
    # node-package-name is the name from the package.json
    npm link <node-package-name>
    

    Check your directory

    Make sure you run npm link <node-name> in the nodes directory within your n8n installation. This can be:

    • ~/.n8n/custom/
    • ~/.n8n/<your-custom-name>: if your n8n installation set a different name using N8N_CUSTOM_EXTENSIONS.
  4. Start n8n:

    1
    n8n start
    

  5. Open n8n in your browser. You should see your nodes when you search for them in the nodes panel.

    Node names

    Make sure you search using the node name, not the package name. For example, if your npm package name is n8n-nodes-weather-nodes, and the package contains nodes named rain, sun, snow, you should search for rain, not weather-nodes.

Troubleshooting#

If there's no custom directory in ~/.n8n local installation, you have to create custom directory manually and run npm init:

1
2
3
4
# In ~/.n8n directory run
mkdir custom 
cd custom 
npm init

下一步步骤#

¥Next steps

¥Deploy your node.

  • 查看程序化节点示例:n8n 的 Mattermost 节点。这是一个更复杂的程序化节点结构示例。

¥View an example of a programmatic node: n8n's Mattermost node. This is an example of a more complex programmatic node structure.

¥Learn about node versioning.

¥Make sure you understand key concepts: item linking and data structures.