跳到主要内容

选择节点开发方式

n8n 有两种节点开发方式:声明式和编程式。新节点默认采用声明式,请优先使用这种方式构建。

声明式:

  • 使用基于 JSON 的语法,编写更简单,降低引入错误的风险。
  • 更适应未来的演进。
  • 支持 REST API 集成。
  • 无需 execute() 方法,减少需要编写和维护的代码。

如果不确定需要哪种方式,请从声明式开始。n8n-node 工具可以生成声明式节点脚手架,构建声明式节点则提供完整示例。

何时需要编程式 ​

编程式代码更多,需要用自行维护的代码实现节点行为,应仅在特殊情况下使用。节点属于以下情况时,使用编程式:

  • 触发节点。
  • 不基于 REST 的节点,包括需要调用 GraphQL API 或使用外部依赖的节点。
  • 需要在路由能力之外转换数据的节点。声明式可以通过 routing.request.preSend 修改请求、通过 routing.output.postReceive 修改 API 响应。如果节点需要独立于单次 API 调用处理输入数据项,请使用编程式。
  • 需要基于功能的版本控制,在代码中通过 this.isNodeFeatureEnabled() 实现不同行为分支的节点。声明式节点仍可使用轻量版本控制,并通过 @feature 在 displayOptions 中读取功能标志。版本控制类型的更多说明,请参阅节点版本控制。

如果节点不属于上述情况,请使用声明式。

信息

触发节点必须使用编程式

声明式不支持触发节点。所有触发节点都必须使用编程式,即使同一服务的操作节点采用声明式。

可以在一个节点软件包中混用两种方式。例如,提交验证的软件包,可以包含同一服务的声明式操作节点和编程式触发节点。

数据处理差异 ​

声明式与编程式的主要区别,在于如何处理输入数据和构建 API 请求。编程式需要 execute() 方法,读取输入数据和参数后构建请求。声明式通过 routing 键处理,该键位于 operations 对象中。节点参数及 execute() 方法的更多信息,请参阅节点基础文件。

语法差异 ​

可比较下面两段代码,理解声明式与编程式的区别。此示例创建了 SendGrid 集成的简化版本,称为“FriendGrid”。代码片段并不完整,只突出两种节点开发方式的差异。

FriendGrid 调用 REST API,且不转换输入,因此适合使用声明式。声明式实现如下:

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

// Create the FriendGrid class
export class FriendGrid implements INodeType {
description: INodeTypeDescription = {
displayName: 'FriendGrid',
name: 'friendGrid',
. . .
// Set up the basic request configuration
requestDefaults: {
baseURL: 'https://api.sendgrid.com/v3/marketing'
},
properties: [
{
displayName: 'Resource',
. . .
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'contact',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a contact',
// Add the routing object
routing: {
request: {
method: 'POST',
url: '=/contacts',
send: {
type: 'body',
properties: {
email: '={{$parameter["email"]}}'
}
}
},
// Handle the response to contact creation
output: {
postReceive: [
{
type: 'set',
properties: {
value: '={{ { "success": $response } }}'
}
}
]
}
}
},
],
default: 'create',
description: 'The operation to perform.',
},
{
displayName: 'Email',
. . .
},
{
displayName: 'Additional Fields',
// Sets up optional fields
},
],
}
// No execute method needed
}

同一节点采用编程式时,需要一个 execute() 方法,手动读取参数并构建请求:

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

// Create the FriendGrid class
export class FriendGrid implements INodeType {
description: INodeTypeDescription = {
displayName: 'FriendGrid',
name: 'friendGrid',
. . .
properties: [
{
displayName: 'Resource',
. . .
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'contact',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a contact',
},
],
default: 'create',
description: 'The operation to perform.',
},
{
displayName: 'Email',
name: 'email',
. . .
},
{
displayName: 'Additional Fields',
// Sets up optional fields
},
],
};

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
let responseData;
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
//Get credentials the user provided for this node
const credentials = await this.getCredentials('friendGridApi') as IDataObject;

if (resource === 'contact') {
if (operation === 'create') {
// Get email input
const email = this.getNodeParameter('email', 0) as string;
// Get additional fields input
const additionalFields = this.getNodeParameter('additionalFields', 0) as IDataObject;
const data: IDataObject = {
email,
};

Object.assign(data, additionalFields);

// Make HTTP request as defined in https://sendgrid.com/docs/api-reference/
const options: IRequestOptions = {
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${credentials.apiKey}`,
},
method: 'PUT',
body: {
contacts: [
data,
],
},
url: `https://api.sendgrid.com/v3/marketing/contacts`,
json: true,
};
responseData = await this.helpers.httpRequest(options);
}
}
// Map data to n8n data
return [this.helpers.returnJsonArray(responseData)];
}
}

相关资源 ​

本文为社区中文翻译。查看对应英文原文