"좋은 보일러플레이트 하나가 수백 시간을 아껴준다."
— 실리콘밸리 개발자 격언import {
IExecuteFunctions,
INodeExecutionData,
INodeType,
INodeTypeDescription,
IHttpRequestOptions,
NodeOperationError,
} from 'n8n-workflow';
export class MyApiNode implements INodeType {
description: INodeTypeDescription = {
displayName: '내 API 노드',
name: 'myApiNode',
group: ['transform'],
version: 1,
description: 'REST API를 호출하는 커스텀 노드',
defaults: { name: '내 API 노드' },
inputs: ['main'],
outputs: ['main'],
credentials: [{ name: 'myApiCredentials', required: true }],
properties: [
{
displayName: '작업',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{ name: '데이터 가져오기', value: 'get' },
{ name: '데이터 만들기', value: 'create' },
],
default: 'get',
},
{
displayName: 'ID',
name: 'id',
type: 'string',
displayOptions: { show: { operation: ['get'] } },
default: '',
required: true,
},
{
displayName: '이름',
name: 'name',
type: 'string',
displayOptions: { show: { operation: ['create'] } },
default: '',
required: true,
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
const credentials = await this.getCredentials('myApiCredentials');
for (let i = 0; i < items.length; i++) {
try {
const operation = this.getNodeParameter('operation', i) as string;
let responseData;
if (operation === 'get') {
const id = this.getNodeParameter('id', i) as string;
const options: IHttpRequestOptions = {
method: 'GET',
url: `${credentials.baseUrl}/items/${id}`,
headers: { Authorization: `Bearer ${credentials.apiKey}` },
};
responseData = await this.helpers.httpRequest(options);
} else if (operation === 'create') {
const name = this.getNodeParameter('name', i) as string;
const options: IHttpRequestOptions = {
method: 'POST',
url: `${credentials.baseUrl}/items`,
headers: {
Authorization: `Bearer ${credentials.apiKey}`,
'Content-Type': 'application/json',
},
body: { name },
json: true,
};
responseData = await this.helpers.httpRequest(options);
}
returnData.push({
json: responseData as Record<string, unknown>,
pairedItem: { item: i },
});
} catch (error) {
if (this.continueOnFail()) {
returnData.push({
json: { error: (error as Error).message },
pairedItem: { item: i },
});
continue;
}
throw new NodeOperationError(this.getNode(), error as Error, { itemIndex: i });
}
}
return [returnData];
}
}