튜토리얼: 선언적 스타일 노드 빌드하기
n8n v2.29이 튜토리얼에서는 선언적 스타일 노드를 빌드하는 과정을 안내합니다. 개발 머신에 다음이 설치되어 있어야 합니다: 이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요. 이 섹션에서는 n8n의 노드 스타터 리포지터리를 클론하고, NASA API를 통합하는 노드를 빌드합니다.
이 튜토리얼에서는 선언적 스타일 노드를 빌드하는 과정을 안내합니다. 시작하기 전에 이것이 필요한 노드 스타일인지 확인하세요. 자세한 내용은 노드 빌드 방식 선택하기를 참조하세요.
사전 준비 사항#
개발 머신에 다음이 설치되어 있어야 합니다:
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.
다음에 대한 이해가 필요합니다:
- JavaScript/TypeScript
- REST API
- git
노드 빌드하기#
이 섹션에서는 n8n의 노드 스타터 리포지터리를 클론하고, NASA API를 통합하는 노드를 빌드합니다. NASA의 두 가지 서비스인 APOD(오늘의 천문 사진, Astronomy Picture of the Day)와 화성 로버 사진(Mars Rover Photos)을 사용하는 노드를 만들게 됩니다. 코드 예제를 간결하게 유지하기 위해, 이 노드는 화성 로버 사진 엔드포인트에서 사용 가능한 모든 옵션을 구현하지는 않습니다.
기존 노드
n8n에는 내장 NASA 노드가 있습니다. 기존 노드와 충돌하지 않도록, 여러분이 만들 버전에는 다른 이름을 지정합니다.
1단계: 프로젝트 설정#
n8n은 노드 개발을 위한 스타터 리포지터리를 제공합니다. 스타터를 사용하면 필요한 모든 의존성을 갖출 수 있습니다. 또한 린터도 제공됩니다.
리포지터리를 클론하고 디렉터리로 이동합니다:
- 템플릿 리포지터리에서 새 리포지터리를 생성합니다.
- 새 리포지터리를 클론합니다:
shell git clone https://github.com/<your-organization>/<your-repo-name>.git n8n-nodes-nasa-pics cd n8n-nodes-nasa-pics
스타터에는 예제 노드와 자격 증명이 포함되어 있습니다. 다음 디렉터리와 파일을 삭제하세요:
nodes/Examplenodes/GithubIssuescredentials/GithubIssuesApi.credentials.tscredentials/GithubIssuesOAuth2Api.credentials.ts
이제 다음 디렉터리와 파일을 생성합니다:
nodes/NasaPics
nodes/NasaPics/NasaPics.node.json
nodes/NasaPics/NasaPics.node.ts
credentials/NasaPicsApi.credentials.ts
이는 모든 노드에 필요한 핵심 파일입니다. 필수 파일과 권장 구성에 대한 자세한 내용은 노드 파일 구조를 참조하세요.
이제 프로젝트 의존성을 설치합니다:
npm i
2단계: 아이콘 추가#
여기에서 NASA SVG 로고를 저장하여 nodes/NasaPics/에 nasapics.svg로 저장합니다.
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.
3단계: 노드 생성#
모든 노드는 기본 파일(base file)을 가져야 합니다. 기본 파일 매개변수에 대한 자세한 내용은 노드 기본 파일을 참조하세요.
이 예제에서 해당 파일은 NasaPics.node.ts입니다. 이 튜토리얼을 간결하게 유지하기 위해, 노드 기능을 모두 이 하나의 파일에 배치합니다. 더 복잡한 노드를 빌드할 때는 기능을 모듈로 분리하는 것을 고려해야 합니다. 자세한 내용은 노드 파일 구조를 참조하세요.
3.1단계: 임포트#
먼저 import 구문을 추가합니다:
import { NodeConnectionTypes } from 'n8n-workflow';
import type { INodeType, INodeTypeDescription } from 'n8n-workflow';
3.2단계: 메인 클래스 생성#
노드는 INodeType을 구현하는 인터페이스를 export해야 합니다. 이 인터페이스는 description 인터페이스를 포함해야 하며, 이 인터페이스는 다시 properties 배열을 포함합니다.
클래스 이름과 파일 이름
클래스 이름과 파일 이름이 일치하는지 확인하세요. 예를 들어, NasaPics라는 클래스가 있다면 파일 이름은 NasaPics.node.ts여야 합니다.
export class NasaPics implements INodeType {
description: INodeTypeDescription = {
// Basic node details will go here
properties: [
// Resources and operations will go here
]
};
}
3.3단계: 노드 세부 정보 추가#
모든 노드에는 표시 이름(display name), 아이콘, 노드를 사용해 요청을 만드는 데 필요한 기본 정보와 같은 몇 가지 기본 매개변수가 필요합니다. description에 다음을 추가하세요:
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',
},
usableAsTool: true,
inputs: [ NodeConnectionTypes.Main ],
outputs: [ NodeConnectionTypes.Main ],
credentials: [
{
name: 'NasaPicsApi',
required: true,
},
],
requestDefaults: {
baseURL: 'https://api.nasa.gov',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
},
n8n은 description에 설정된 속성 중 일부를 사용하여 에디터 UI에 노드를 렌더링합니다. 이 속성들은 displayName, icon, description, subtitle입니다.
3.4단계: 리소스 추가#
리소스 객체는 노드가 사용하는 API 리소스를 정의합니다. 이 튜토리얼에서는 NASA API 엔드포인트 중 두 가지인 planetary/apod와 mars-photos에 액세스하는 노드를 만듭니다. 즉, NasaPics.node.ts에서 두 개의 리소스 옵션을 정의해야 합니다. properties 배열을 리소스 객체로 업데이트합니다:
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 요소를 참조하세요.
3.5단계: 오퍼레이션 추가#
오퍼레이션 객체는 리소스에서 사용 가능한 오퍼레이션을 정의합니다.
선언적 스타일 노드에서 오퍼레이션 객체는 (options 배열 내에) routing을 포함합니다. 이는 API 호출의 세부 사항을 설정합니다.
resource 객체 뒤에 properties 배열에 다음을 추가합니다:
{
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을 생성합니다.
3.6단계: 선택적 필드#
이 예제에서 사용하는 NASA API를 포함한 대부분의 API에는 쿼리를 세부적으로 조정하는 데 사용할 수 있는 선택적 필드가 있습니다.
사용자에게 과도한 정보를 제공하지 않기 위해, n8n은 UI에서 이러한 필드를 Additional Fields(추가 필드) 아래에 표시합니다.
이 튜토리얼에서는 사용자가 APOD 엔드포인트와 함께 사용할 날짜를 선택할 수 있도록 추가 필드 하나를 추가합니다. properties 배열에 다음을 추가합니다:
{
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단계: 인증 및 자격 증명 테스트 설정#
NASA API는 사용자가 API 키로 인증하도록 요구합니다. API 키가 작동하는지 확인하는 요청을 보낼 수도 있습니다.
nasaPicsApi.credentials.ts에 다음을 추가합니다:
import {
IAuthenticateGeneric,
ICredentialTestRequest,
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://docs.n8n.io/integrations/creating-nodes/build/declarative-style-node/';
properties: INodeProperties[] = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string',
default: '',
},
];
authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
qs: {
'api_key': '={{$credentials.apiKey}}'
}
},
};
test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.nasa.gov',
url: '/apod',
},
};
}
자격 증명 파일과 옵션에 대한 자세한 내용은 자격 증명 파일을 참조하세요.
5단계: 노드 메타데이터 추가#
노드에 대한 메타데이터는 노드 루트에 있는 JSON 파일에 들어갑니다. n8n은 이를 코덱스 파일(codex file)이라고 부릅니다. 이 예제에서 해당 파일은 NasaPics.node.json입니다.
JSON 파일에 다음 코드를 추가합니다:
{
"node": "n8n-nodes-nasapics",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": [
"Miscellaneous"
],
"resources": {
"credentialDocumentation": [
{
"url": ""
}
],
"primaryDocumentation": [
{
"url": ""
}
]
}
}
이러한 매개변수에 대한 자세한 내용은 노드 코덱스 파일을 참조하세요.
6단계: npm 패키지 세부 정보 업데이트#
npm 패키지 세부 정보는 프로젝트 루트의 package.json에 있습니다. 자격 증명 및 기본 노드 파일에 대한 링크가 있는 n8n 객체를 포함하는 것이 필수입니다. 다음 정보를 포함하도록 이 파일을 업데이트하세요:
{
// 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.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/NasaPicsApi.credentials.js"
],
"nodes": [
"dist/nodes/NasaPics/NasaPics.node.js"
]
},
"devDependencies": {
// don't change
},
"peerDependencies": {
// don't change
}
}
자신의 이름, 리포지터리 URL 등 자신만의 정보를 포함하도록 package.json을 업데이트해야 합니다. npm package.json 파일에 대한 자세한 내용은 npm의 package.json 문서를 참조하세요.
노드 테스트하기#
이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.