튜토리얼: 프로그래밍 방식(programmatic-style) 노드 빌드하기
n8n v2.29이 튜토리얼에서는 프로그래밍 방식 노드를 빌드하는 과정을 설명합니다. 개발 머신에 다음 항목이 설치되어 있어야 합니다: 이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요. 다음 항목에 대한 이해가 필요합니다: 이 섹션에서는 n8n의 노드 스타터 리포지터리를 클론하고, SendGrid와 연동하는 노드를 빌드합니다.
이 튜토리얼에서는 프로그래밍 방식 노드를 빌드하는 과정을 설명합니다. 시작하기 전에 이것이 필요한 노드 스타일인지 확인하세요. 자세한 내용은 노드 빌드 방식 선택하기를 참고하세요.
사전 준비 사항#
개발 머신에 다음 항목이 설치되어 있어야 합니다:
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.
다음 항목에 대한 이해가 필요합니다:
- JavaScript/TypeScript
- REST API
- git
- n8n의 표현식1
노드 빌드하기#
이 섹션에서는 n8n의 노드 스타터 리포지터리를 클론하고, SendGrid와 연동하는 노드를 빌드합니다. SendGrid 기능 중 하나인 연락처 생성을 구현하는 노드를 만들게 됩니다.
기존 노드
n8n에는 기본 제공되는 SendGrid 노드가 있습니다. 기존 노드와 충돌하지 않도록, 여러분이 만드는 버전에는 다른 이름을 붙입니다.
1단계: 프로젝트 설정하기#
n8n은 노드 개발을 위한 스타터 리포지터리를 제공합니다. 스타터를 사용하면 필요한 모든 의존성을 갖출 수 있습니다. 또한 린터(linter)도 제공됩니다.
리포지터리를 클론하고 디렉터리로 이동합니다:
- 템플릿 리포지터리에서 새 리포지터리를 생성합니다.
- 새 리포지터리를 클론합니다:
shell git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-friendgrid cd n8n-nodes-friendgrid
스타터에는 예제 노드와 자격 증명이 포함되어 있습니다. 다음 디렉터리와 파일을 삭제하세요:
nodes/Examplenodes/GithubIssuescredentials/GithubIssuesApi.credentials.tscredentials/GithubIssuesOAuth2Api.credentials.ts
이제 다음 디렉터리와 파일을 만듭니다:
nodes/FriendGrid
nodes/FriendGrid/FriendGrid.node.json
nodes/FriendGrid/FriendGrid.node.ts
credentials/FriendGridApi.credentials.ts
이는 모든 노드에 필요한 핵심 파일입니다. 필수 파일과 권장 구성에 대한 자세한 내용은 노드 파일 구조를 참고하세요.
이제 프로젝트 의존성을 설치합니다:
npm i
2단계: 아이콘 추가하기#
여기에서 SendGrid SVG 로고를 저장하여 nodes/FriendGrid/에 friendGrid.svg로 저장합니다.
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.
3단계: 베이스 파일에서 노드 정의하기#
모든 노드는 베이스 파일을 가져야 합니다. 베이스 파일 파라미터에 대한 자세한 내용은 노드 베이스 파일을 참고하세요.
이 예제에서 해당 파일은 FriendGrid.node.ts입니다. 이 튜토리얼을 간결하게 유지하기 위해, 모든 노드 기능을 이 하나의 파일에 배치합니다. 더 복잡한 노드를 빌드할 때는 기능을 모듈로 분리하는 것을 고려해야 합니다. 자세한 내용은 노드 파일 구조를 참고하세요.
3.1단계: 임포트(Imports)#
import 문을 추가하는 것으로 시작합니다:
import type {
IDataObject,
IExecuteFunctions,
IHttpRequestOptions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
3.2단계: 메인 클래스 생성하기#
노드는 INodeType을 구현하는 인터페이스를 내보내야 합니다. 이 인터페이스에는 description 인터페이스가 포함되어야 하며, 이 인터페이스는 다시 properties 배열을 포함합니다.
클래스 이름과 파일 이름
클래스 이름과 파일 이름이 일치하는지 확인하세요. 예를 들어 FriendGrid라는 클래스가 있다면, 파일 이름은 FriendGrid.node.ts여야 합니다.
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단계: 노드 세부 정보 추가하기#
모든 프로그래밍 방식 노드에는 표시 이름과 아이콘 같은 기본 파라미터가 필요합니다. description에 다음을 추가합니다:
displayName: 'FriendGrid',
name: 'friendGrid',
icon: 'file:friendGrid.svg',
group: ['transform'],
version: 1,
description: 'Consume SendGrid API',
defaults: {
name: 'FriendGrid',
},
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
usableAsTool: true,
credentials: [
{
name: 'friendGridApi',
required: true,
},
],
n8n은 description에 설정된 속성 일부를 사용하여 Editor UI에서 노드를 렌더링합니다. 이러한 속성은 displayName, icon, description입니다.
3.4단계: 리소스 추가하기#
resource 객체는 노드가 사용하는 API 리소스를 정의합니다. 이 튜토리얼에서는 SendGrid API 엔드포인트 중 하나인 /v3/marketing/contacts에 접근하는 노드를 만들고 있습니다. 즉, 이 엔드포인트에 대한 리소스를 정의해야 합니다. properties 배열에 resource 객체를 추가합니다:
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Contact',
value: 'contact',
},
],
default: 'contact',
noDataExpression: true,
required: true,
description: 'Create a new contact',
},
type은 n8n이 resource에 대해 표시할 UI 요소를 제어하며, 사용자로부터 어떤 종류의 데이터를 받을지 n8n에 알려줍니다. options를 사용하면 n8n이 사용자가 하나의 옵션을 선택할 수 있는 드롭다운을 추가합니다. 자세한 내용은 노드 UI 요소를 참고하세요.
3.5단계: 오퍼레이션 추가하기#
operation 객체는 리소스로 할 수 있는 작업을 정의합니다. 이는 보통 REST API 동사(GET, POST 등)와 관련이 있습니다. 이 튜토리얼에서는 오퍼레이션이 하나 있습니다: 연락처 생성. 여기에는 필수 필드가 하나 있는데, 사용자가 생성하는 연락처의 이메일 주소입니다.
resource 객체 다음에 properties 배열에 다음을 추가합니다:
{
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단계: 선택적 필드 추가하기#
이 예제에서 사용하는 SendGrid API를 포함해 대부분의 API에는 쿼리를 세부적으로 조정할 수 있는 선택적 필드가 있습니다.
사용자에게 너무 많은 정보를 한 번에 보여주지 않기 위해, n8n은 이러한 필드를 UI에서 Additional Fields 아래에 표시합니다.
이 튜토리얼에서는 사용자가 연락처의 이름(first name)과 성(last name)을 입력할 수 있도록 선택적 필드 두 개를 추가합니다. properties 배열에 다음을 추가합니다:
{
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 메서드 추가하기#
노드 UI와 기본 정보를 설정했습니다. 이제 노드 UI를 API 요청에 매핑하여, 노드가 실제로 무언가를 수행하도록 만들 차례입니다.
execute 메서드는 노드가 실행될 때마다 실행됩니다. 이 메서드 안에서는 입력 항목과, 자격 증명을 포함해 사용자가 UI에서 설정한 파라미터에 접근할 수 있습니다.
FriendGrid.node.ts의 execute 메서드에 다음을 추가합니다:
// Handle data coming from previous nodes
const items = this.getInputData();
let responseData;
const returnData: INodeExecutionData[] = [];
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
// For each item, make an API call to create a contact
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'contact') {
if (operation === 'create') {
// Get email input
const email = this.getNodeParameter('email', i);
// Get additional fields input
const additionalFields = this.getNodeParameter('additionalFields', i);
const data: IDataObject = {
email,
};
Object.assign(data, additionalFields);
// Make HTTP request according to https://sendgrid.com/docs/api-reference/
const options: IHttpRequestOptions = {
headers: {
'Accept': 'application/json',
},
method: 'PUT',
body: {
contacts: [
data,
],
},
url: 'https://api.sendgrid.com/v3/marketing/contacts',
json: true,
};
responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'friendGridApi', options);
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject),
{ itemData: { item: i } },
);
returnData.push.apply(returnData, executionData);
}
}
} catch (error) {
if (this.continueOnFail()) {
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push.apply(returnData, executionData);
continue;
}
throw error;
}
}
return [returnData];
이 코드에서 다음 줄을 주목하세요:
const items = this.getInputData();
...
for (let i = 0; i < items.length; i++) {
...
const email = this.getNodeParameter('email', i);
...
}
사용자는 다음 두 가지 방법으로 데이터를 제공할 수 있습니다:
- 노드 필드에 직접 입력
- 워크플로의 이전 노드에서 데이터를 매핑
getInputData()와 그 뒤를 잇는 반복문을 통해, 노드는 이전 노드에서 데이터가 오는 상황을 처리할 수 있습니다. 여기에는 여러 입력을 지원하는 것도 포함됩니다. 즉, 예를 들어 이전 노드가 다섯 명에 대한 연락처 정보를 출력하면, FriendGrid 노드는 연락처 다섯 개를 생성할 수 있습니다.
5단계: 인증 설정하기#
SendGrid API는 사용자가 API 키로 인증하도록 요구합니다.
FriendGridApi.credentials.ts에 다음을 추가합니다
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',
},
};
}
자격 증명 파일과 옵션에 대한 자세한 내용은 자격 증명 파일을 참고하세요.
6단계: 노드 메타데이터 추가하기#
노드에 대한 메타데이터는 노드 루트에 있는 JSON 파일에 들어갑니다. n8n에서는 이를 코덱스(codex) 파일이라고 부릅니다. 이 예제에서 해당 파일은 FriendGrid.node.json입니다.
JSON 파일에 다음 코드를 추가합니다:
{
"node": "n8n-nodes-friendgrid",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Miscellaneous"
],
"resources": {
"credentialDocumentation": [
{
"url": ""
}
],
"primaryDocumentation": [
{
"url": ""
}
]
}
}
이러한 파라미터에 대한 자세한 내용은 노드 코덱스 파일을 참고하세요.
7단계: npm 패키지 세부 정보 업데이트하기#
npm 패키지 세부 정보는 프로젝트 루트에 있는 package.json에 있습니다. 자격 증명 파일과 베이스 노드 파일에 대한 링크가 포함된 n8n 객체를 포함하는 것이 필수적입니다. 다음 정보를 포함하도록 이 파일을 업데이트합니다:
{
// 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.io",
"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
}
}
이름과 리포지터리 URL 등 자신의 정보를 포함하도록 package.json을 업데이트해야 합니다. npm의 package.json 파일에 대한 자세한 내용은 npm의 package.json 문서를 참고하세요.
노드 테스트하기#
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.
다음 단계#
- 노드 배포하기.
- 프로그래밍 방식 노드의 예시 확인: n8n의 Mattermost 노드. 이는 더 복잡한 프로그래밍 방식 노드 구조의 예시입니다.
- 노드 버전 관리에 대해 알아보세요.
- 다음 핵심 개념을 이해하고 있는지 확인하세요: 아이템 연결(item linking) 및 데이터 구조.
Footnotes
-
n8n에서 표현식을 사용하면 JavaScript 코드를 실행하여 노드 파라미터를 동적으로 채울 수 있습니다. 정적인 값을 제공하는 대신, n8n 표현식 구문을 사용해 이전 노드, 다른 워크플로, 또는 n8n 환경의 데이터를 이용해 값을 정의할 수 있습니다. ↩