Skip to content

构建声明式风格节点#

¥Build a declarative-style node

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

¥This tutorial walks through building a declarative-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

构建节点#

¥Build your node

在本部分中,你将克隆 n8n 的节点入门存储库,并构建一个集成 NASA API 的节点。你将创建一个节点来使用 NASA 的两项服务:每日天文图片 (APOD) 和火星探测车照片。为了保持代码示例简洁,节点不会实现火星探测器照片端点的所有可用选项。

¥In this section, you'll clone n8n's node starter repository, and build a node that integrates the NASA API. You'll create a node that uses two of NASA's services: APOD (Astronomy Picture of the Day) and Mars Rover Photos. To keep the code examples short, the node won't implement every available option for the Mars Rover Photos endpoint.

Existing node

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

¥n8n has a built-in NASA 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-nasa-pics cd n8n-nodes-nasa-pics

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

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

¥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/NasaPics nodes/NasaPics/NasaPics.node.json nodes/NasaPics/NasaPics.node.ts credentials/NasaPicsApi.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

此处 中的 NASA SVG 徽标保存为 nodes/NasaPics/ 中的 nasapics.svg

¥Save the NASA SVG logo from here as nasapics.svg in nodes/NasaPics/.

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: Create the node

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

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

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

¥In this example, the file is NasaPics.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
import { INodeType, INodeTypeDescription } from 'n8n-workflow';

步骤 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

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

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

1
2
3
4
5
6
7
8
export class NasaPics implements INodeType {
	description: INodeTypeDescription = {
		// Basic node details will go here
		properties: [
		// Resources and operations will go here
		]
	};
}

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

¥Step 3.3: Add node details

所有节点都需要一些基本参数,例如显示名称、图标以及使用该节点发出请求所需的基本信息。将以下内容添加到 description

¥All nodes need some basic parameters, such as their display name, icon, and the basic information for making a request using the node. Add the following to the description:

 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
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',
	},
},

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

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

步骤 3.4:添加资源#

¥Step 3.4: Add resources

资源对象定义了节点使用的 API 资源。在本教程中,你将创建一个节点来访问 NASA 的两个 API 端点:planetary/apodmars-photos。这意味着你需要在 NasaPics.node.ts 中定义两个资源选项。使用资源对象更新 properties 数组:

¥The resource object defines the API resource that the node uses. In this tutorial, you're creating a node to access two of NASA's API endpoints: planetary/apod and mars-photos. This means you need to define two resource options in NasaPics.node.ts. Update the properties array with the resource object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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',
	},
	// Operations will go here

]

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

操作对象定义了资源的可用操作。

¥The operations object defines the available operations on a resource.

在声明式节点中,操作对象包含 routing(位于 options 数组中)。此设置用于设置 API 调用的详细信息。

¥In a declarative-style node, the operations object includes routing (within the options array). This sets up the details of the API call.

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
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
{
	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) }}',
			},
		},
	},
},
// Optional/additional fields will go here

此代码创建两个操作:一个用于获取今日每日天文图 (APOD) 图片,另一个用于向火星探测车发送照片 GET 请求。名为 roverName 的对象要求用户选择要从中获取照片的漫游车。火星探测车操作中的 routing 对象引用此链接以创建 API 调用的 URL。

¥This code creates two operations: one to get today's APOD image, and another to send a get request for photos from one of the Mars Rovers. The object named roverName requires the user to choose which Rover they want photos from. The routing object in the Mars Rover operation references this to create the URL for the API call.

步骤 3.6:可选字段#

¥Step 3.6: Optional fields

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

¥Most APIs, including the NASA 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.

在本教程中,你将添加一个额外的字段,允许用户选择要与 APOD 端点一起使用的日期。将以下内容添加到 properties 数组:

¥For this tutorial, you'll add one additional field, to allow users to pick a date to use with the APOD endpoint. 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
32
33
{
	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) }}',
					},
				},
			},
		},
	],									
}

步骤 4:设置身份验证#

¥Step 4: Set up authentication

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

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

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

¥Add the following to nasaPicsApi.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
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://n8n.nodejs.cn/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;
}

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

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

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

¥Step 5: Add node metadata

关于节点的元数据位于节点根目录下的 JSON 文件中。n8n 将此称为 codex 文件。本示例中,文件为 NasaPics.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 NasaPics.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.NasaPics",
	"nodeVersion": "1.0",
	"codexVersion": "1.0",
	"categories": [
		"Miscellaneous"
	],
	"resources": {
		"credentialDocumentation": [
			{
				"url": ""
			}
		],
		"primaryDocumentation": [
			{
				"url": ""
			}
		]
	}
}

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

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

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

¥Step 6: 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-nasapics",
	"version": "0.1.0",
	"description": "n8n node to call NASA's APOD and Mars Rover Photo services.",
	"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/NasaPicsApi.credentials.js"
		],
		"nodes": [
			"dist/nodes/NasaPics/NasaPics.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 的 Brevo 节点。请注意,主节点是声明式的,而触发节点是程序式的。

¥View an example of a declarative node: n8n's Brevo node. Note that the main node is declarative, while the trigger node is in programmatic style.

¥Learn about node versioning.