프로그래매틱 스타일 node 빌드
이 튜토리얼은 프로그래매틱 스타일 node 빌드 과정을 안내합니다. 개발 컴퓨터에 다음이 설치되어 있어야 합니다: 이 섹션에서는 n8n의 node 스타터 저장소를 클론하고 SendGrid를 통합하는 node를 빌드합니다.
이 튜토리얼은 프로그래매틱 스타일 node 빌드 과정을 안내합니다. 시작하기 전에 이것이 필요한 node 스타일인지 확인합니다. 자세한 내용은 Node 빌드 방식 선택을 참고하세요.
사전 요구 사항#
개발 컴퓨터에 다음이 설치되어 있어야 합니다:
- git
- Node.js 및 npm. 최소 버전은 Node 18.17.0입니다. Linux, Mac, WSL에서 nvm(Node Version Manager)을 사용하여 두 가지를 설치하는 방법은 여기에서 확인할 수 있습니다. Windows 사용자는 Microsoft의 Windows에 NodeJS 설치 가이드를 참고하세요.
다음 사항을 이해해야 합니다:
- JavaScript/TypeScript
- REST API
- git
- n8n의 표현식
Node 빌드#
이 섹션에서는 n8n의 node 스타터 저장소를 클론하고 SendGrid를 통합하는 node를 빌드합니다. 하나의 SendGrid 기능인 연락처 생성을 구현하는 node를 생성합니다.
n8n에는 내장 SendGrid node가 있습니다. 기존 node와 충돌을 피하기 위해 다른 이름을 부여합니다.
1단계: 프로젝트 설정#
n8n은 node 개발을 위한 스타터 저장소를 제공합니다. 스타터를 사용하면 필요한 모든 종속성을 갖출 수 있습니다. 또한 린터도 제공됩니다.
저장소를 클론하고 디렉터리로 이동합니다:
- 템플릿 저장소에서 새 저장소를 생성합니다.
- 새 저장소를 클론합니다:
shell git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-friendgrid cd n8n-nodes-friendgrid
스타터에는 예시 node와 자격 증명이 포함되어 있습니다. 다음 디렉터리와 파일을 삭제합니다:
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
이것들은 모든 node에 필요한 핵심 파일입니다. 필수 파일 및 권장 구성에 대한 자세한 내용은 Node 파일 구조를 참고하세요.
이제 프로젝트 종속성을 설치합니다:
npm i
2단계: 아이콘 추가#
여기에서 SendGrid SVG 로고를 nodes/FriendGrid/에 friendGrid.svg로 저장합니다.
n8n은 노드 아이콘으로 SVG 사용을 권장하지만, PNG도 사용할 수 있습니다. PNG를 사용하는 경우 아이콘 해상도는 60x60px여야 합니다. 노드 아이콘은 정사각형 또는 정사각형에 가까운 비율이어야 합니다.
노드에 Font Awesome 아이콘을 사용하려면 이미지를 다운로드하여 임베드하세요.
3단계: 기본 파일에서 node 정의#
모든 node에는 기본 파일이 있어야 합니다. 기본 파일 파라미터에 대한 자세한 내용은 Node 기본 파일을 참고하세요.
이 예시에서 파일은 FriendGrid.node.ts입니다. 이 튜토리얼을 짧게 유지하기 위해 모든 node 기능을 이 하나의 파일에 배치합니다. 더 복잡한 node를 빌드할 때는 기능을 모듈로 분리하는 것을 고려해야 합니다. 자세한 내용은 Node 파일 구조를 참고하세요.
3.1단계: Import#
import 문을 추가하는 것으로 시작합니다:
import type {
IDataObject,
IExecuteFunctions,
IHttpRequestOptions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
3.2단계: 메인 클래스 생성#
node는 INodeType을 구현하는 인터페이스를 export해야 합니다. 이 인터페이스에는 properties 배열을 포함하는 description 인터페이스가 있어야 합니다.
클래스 이름과 파일 이름이 일치하는지 확인합니다. 예를 들어, FriendGrid 클래스가 있으면 파일 이름은 FriendGrid.node.ts여야 합니다.
export class FriendGrid implements INodeType {
description: INodeTypeDescription = {
// 기본 node 세부 정보가 여기에 들어감
properties: [
// 리소스와 오퍼레이션이 여기에 들어감
],
};
// execute 메서드가 여기에 들어감
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
}
}
3.3단계: Node 세부 정보 추가#
모든 프로그래매틱 node에는 표시 이름과 아이콘 같은 기본 파라미터가 필요합니다. 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에 설정된 일부 속성을 사용하여 편집기 UI에서 node를 렌더링합니다. 이 속성들은 displayName, icon, description입니다.
3.4단계: 리소스 추가#
리소스 오브젝트는 node가 사용하는 API 리소스를 정의합니다. 이 튜토리얼에서는 SendGrid의 API 엔드포인트 중 하나인 /v3/marketing/contacts에 액세스하는 node를 생성합니다. 즉, 이 엔드포인트에 대한 리소스를 정의해야 합니다. properties 배열을 리소스 오브젝트로 업데이트합니다:
{
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 요소를 제어하고 사용자로부터 기대하는 데이터 타입을 알립니다. options는 n8n이 사용자가 하나의 옵션을 선택할 수 있는 드롭다운을 추가하게 합니다. 자세한 내용은 Node UI 요소를 참고하세요.
3.5단계: 오퍼레이션 추가#
오퍼레이션 오브젝트는 리소스에서 수행할 수 있는 것을 정의합니다. 일반적으로 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 아래에 이를 표시합니다.
이 튜토리얼에서는 사용자가 연락처의 이름과 성을 입력할 수 있도록 두 개의 추가 필드를 추가합니다. 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 메서드 추가#
node UI와 기본 정보를 설정했습니다. 이제 node UI를 API 요청에 매핑하고 node가 실제로 무언가를 수행하게 할 시간입니다.
execute 메서드는 node가 실행될 때마다 실행됩니다. 이 메서드에서는 입력 항목과 사용자가 UI에서 설정한 파라미터(자격 증명 포함)에 액세스할 수 있습니다.
FriendGrid.node.ts의 execute 메서드에 다음을 추가합니다:
// 이전 node에서 오는 데이터 처리
const items = this.getInputData();
let responseData;
const returnData: INodeExecutionData[] = [];
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
// 각 항목에 대해 연락처 생성 API 호출
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'contact') {
if (operation === 'create') {
// 이메일 입력 가져오기
const email = this.getNodeParameter('email', i);
// 추가 필드 입력 가져오기
const additionalFields = this.getNodeParameter('additionalFields', i);
const data: IDataObject = {
email,
};
Object.assign(data, additionalFields);
// https://sendgrid.com/docs/api-reference/에 따른 HTTP 요청
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);
...
}
사용자는 두 가지 방법으로 데이터를 제공할 수 있습니다:
- node 필드에 직접 입력
- 워크플로의 이전 node에서 데이터 매핑
getInputData()와 후속 루프를 통해 node는 데이터가 이전 node에서 오는 상황을 처리할 수 있습니다. 여기에는 여러 입력 지원이 포함됩니다. 예를 들어, 이전 node가 다섯 명의 연락처 정보를 출력하면 FriendGrid node는 다섯 개의 연락처를 생성할 수 있습니다.
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단계: Node 메타데이터 추가#
node에 대한 메타데이터는 node 루트의 JSON 파일에 들어갑니다. n8n은 이를 codex 파일이라고 합니다. 이 예시에서 파일은 FriendGrid.node.json입니다.
JSON 파일에 다음 코드를 추가합니다:
{
"node": "n8n-nodes-base.FriendGrid",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Miscellaneous"
],
"resources": {
"credentialDocumentation": [
{
"url": ""
}
],
"primaryDocumentation": [
{
"url": ""
}
]
}
}
이 파라미터에 대한 자세한 내용은 Node codex 파일을 참고하세요.
7단계: npm 패키지 세부 정보 업데이트#
npm 패키지 세부 정보는 프로젝트 루트의 package.json에 있습니다. 자격 증명 및 기본 node 파일에 대한 링크가 있는 n8n 오브젝트를 포함하는 것이 필수입니다. 다음 정보를 포함하도록 이 파일을 업데이트합니다:
{
// 모든 node 이름은 "n8n-nodes-"로 시작해야 함
"name": "n8n-nodes-friendgrid",
"version": "0.1.0",
"description": "n8n node to create contacts in SendGrid",
"keywords": [
// 이 키워드는 커뮤니티 node에 필수
"n8n-community-node-package"
],
"license": "MIT",
"homepage": "https://n8n.io",
"author": {
"name": "Test",
"email": "test@example.com"
},
"repository": {
"type": "git",
// git remote를 자체 저장소로 변경
// 여기에 새 URL 추가
"url": "git+<your-repo-url>"
},
"main": "index.js",
"scripts": {
// 변경하지 않음
},
"files": [
"dist"
],
// 자격 증명과 node 연결
"n8n": {
"n8nNodesApiVersion": 1,
"credentials": [
"dist/credentials/FriendGridApi.credentials.js"
],
"nodes": [
"dist/nodes/FriendGrid/FriendGrid.node.js"
]
},
"devDependencies": {
// 변경하지 않음
},
"peerDependencies": {
// 변경하지 않음
}
}
이름, 저장소 URL과 같은 자체 정보를 포함하도록 package.json을 업데이트해야 합니다. npm package.json 파일에 대한 자세한 내용은 npm의 package.json 문서를 참고하세요.
Node 테스트#
로컬 n8n 인스턴스에서 실행하여 노드를 만들면서 테스트할 수 있습니다.
- npm으로 n8n을 설치합니다:
npm install n8n -g
- 노드를 테스트할 준비가 되면 로컬에 배포합니다:
# 노드 디렉토리 내에서
npm run build
npm link
- 로컬 n8n 인스턴스에 노드를 설치합니다:
# n8n 설치 디렉토리 내 nodes 폴더에서
# node-package-name은 package.json의 이름입니다
npm link <node-package-name>
n8n 설치 디렉토리 내 nodes 폴더에서 npm link <node-name>을 실행하세요. 위치는 다음과 같습니다:
* `~/.n8n/custom/`
* `~/.n8n/<your-custom-name>`: n8n 설치 시 `N8N_CUSTOM_EXTENSIONS`로 다른 이름을 설정한 경우.
- n8n을 시작합니다:
n8n start
- 브라우저에서 n8n을 엽니다. 노드 패널에서 검색하면 노드가 표시됩니다.
패키지 이름이 아닌 노드 이름으로 검색하세요. 예를 들어 npm 패키지 이름이 n8n-nodes-weather-nodes이고 패키지에 rain, sun, snow라는 노드가 있다면 weather-nodes가 아닌 rain으로 검색해야 합니다.
문제 해결#
~/.n8n 로컬 설치에 custom 디렉토리가 없으면 수동으로 custom 디렉토리를 생성하고 npm init을 실행해야 합니다:
# ~/.n8n 디렉토리에서 실행
mkdir custom
cd custom
npm init
다음 단계#
- Node 배포.
- 프로그래매틱 node의 예시를 확인합니다: n8n의 Mattermost node. 더 복잡한 프로그래매틱 node 구조의 예시입니다.
- node 버전 관리에 대해 알아봅니다.
- 핵심 개념을 이해했는지 확인합니다: 항목 연결과 데이터 구조.
