G: 안녕하세요, n8n 자동화 마스터를 꿈꾸는 여러분! 🚀
n8n은 코딩 지식 없이도 강력한 워크플로우를 구축할 수 있게 해주는 놀라운 도구입니다. 하지만 때로는 기본 노드만으로는 해결하기 어려운 복잡한 로직이나 데이터 처리가 필요할 때가 있죠. 이럴 때 워크플로우의 진정한 잠재력을 폭발시킬 수 있는 “비밀 병기”가 있습니다. 바로 Code Node입니다!
오늘은 n8n Code Node를 완벽하게 마스터하여 워크플로우의 한계를 뛰어넘는 비법을 여러분께 아낌없이 공개하겠습니다. 최신 정보를 바탕으로 자세한 예시와 함께 쉽고 재미있게 알아보시죠! 🎉
💡 Code Node, 왜 필요할까요?
n8n의 수많은 기본 노드들은 대부분의 자동화 작업을 커버합니다. 하지만 다음과 같은 상황에서는 Code Node가 빛을 발합니다.
- 복잡한 데이터 변환 및 가공: 여러 필드를 조합하거나, 특정 조건에 따라 데이터를 동적으로 변경해야 할 때 유용합니다.
- 사용자 정의 로직 구현: 특정 비즈니스 규칙에 따라 워크플로우의 흐름을 제어하거나, 데이터를 분류해야 할 때 필요합니다.
- 외부 라이브러리 활용 (고급): 내장된 기능으로는 부족한 경우, npm 패키지를 설치하여 외부 라이브러리의 기능을 활용할 수 있습니다.
- 조건부 실행 및 루프 제어: If Node나 Split In Batches Node만으로는 부족한 정교한 조건이나 반복 처리가 필요할 때 강력합니다.
- 디버깅 및 로깅: 워크플로우 실행 중 특정 데이터를 확인하거나 로그를 남겨야 할 때
console.log
와 함께 사용됩니다.
결론적으로 Code Node는 n8n의 “DIY (Do It Yourself)” 도구라고 생각하시면 됩니다. 표준 도구로는 부족할 때 직접 나만의 도구를 만들어 쓰는 거죠! 🛠️
✨ 시작하기: Code Node의 기본!
Code Node는 JavaScript (또는 TypeScript) 코드를 실행할 수 있는 환경을 제공합니다. n8n 워크플로우에서 Code Node를 추가하고 더블클릭하면 다음과 같은 편집 화면이 나타납니다.
// Code Node의 기본 형태
for (const item of items) {
// 여기에 여러분의 로직을 작성하세요.
// item.json은 현재 아이템의 데이터입니다.
}
return items; // 처리된 아이템 배열을 반환해야 합니다.
여기서 가장 중요한 두 가지 개념은 items
와 return items;
입니다.
-
items
배열:- Code Node로 들어오는 모든 데이터는
items
라는 이름의 배열 형태로 제공됩니다. - 각
item
은{ json: {}, binary: {} }
구조를 가집니다. 일반적으로 우리가 다루는 텍스트 데이터는item.json
안에 객체 형태로 들어있습니다. item.binary
는 파일과 같은 바이너리 데이터를 포함합니다 (주로 File Transfer, S3 Node 등과 함께 사용).
- Code Node로 들어오는 모든 데이터는
-
return items;
:- Code Node는 항상
items
배열을 반환해야 합니다. 이 반환된items
배열이 다음 노드로 전달됩니다. - 만약 아무것도 반환하지 않거나 다른 형태의 데이터를 반환하면 오류가 발생하거나 워크플로우가 예상대로 작동하지 않을 수 있습니다.
- Code Node는 항상
예시 1: 간단한 데이터 변환 (필드 추가하기)
들어오는 각 데이터(아이템)에 status
필드를 추가하고 “processed” 값을 넣어보겠습니다.
-
입력 데이터 (JSON):
[ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" } ]
-
Code Node 코드:
// 들어온 모든 아이템을 순회합니다. for (const item of items) { // 각 아이템의 json 객체에 'status' 필드를 추가하고 값을 할당합니다. item.json.status = 'processed'; // console.log()는 디버깅에 유용합니다. Test Run 시 Output 탭에서 확인할 수 있습니다. console.log(`Processing item ID: ${item.json.id}`); } // 처리된 아이템 배열을 다음 노드로 전달합니다. return items;
-
출력 데이터 (JSON):
[ { "id": 1, "name": "Alice", "status": "processed" }, { "id": 2, "name": "Bob", "status": "processed" } ]
📝 items 배열 완벽 활용하기
items
배열은 JavaScript의 배열 메서드를 통해 강력하게 조작할 수 있습니다. map
, filter
, reduce
등 익숙한 메서드들을 적극 활용해 보세요.
예시 2: 특정 조건에 맞는 데이터만 필터링하기
age
필드가 30을 초과하는 사용자만 다음 노드로 전달하고 싶을 때:
-
입력 데이터:
[ { "name": "Alice", "age": 25 }, { "name": "Bob", "age": 32 }, { "name": "Charlie", "age": 28 }, { "name": "David", "age": 40 } ]
-
Code Node 코드:
// Array.prototype.filter() 메서드를 사용하여 조건을 만족하는 아이템만 필터링합니다. const filteredItems = items.filter(item => { return item.json.age > 30; // age 필드가 30보다 큰 아이템만 남깁니다. }); return filteredItems;
-
출력 데이터:
[ { "name": "Bob", "age": 32 }, { "name": "David", "age": 40 } ]
예시 3: 복잡한 데이터 변환 (생년월일로 나이 계산하기)
birthYear
필드를 이용하여 현재 나이를 계산하고 age
필드를 추가해 보겠습니다.
-
입력 데이터:
[ { "name": "Emily", "birthYear": 1990 }, { "name": "Frank", "birthYear": 2000 } ]
-
Code Node 코드:
const currentYear = new Date().getFullYear(); // 현재 연도를 가져옵니다. const transformedItems = items.map(item => { // birthYear가 존재하면 나이를 계산하고, 없으면 null 등으로 처리합니다. if (item.json.birthYear) { item.json.age = currentYear - item.json.birthYear; } else { item.json.age = null; // 또는 다른 기본값 } return item; // 변환된 아이템을 반환합니다. }); return transformedItems;
-
출력 데이터:
[ { "name": "Emily", "birthYear": 1990, "age": 34 }, // 2024년 기준 { "name": "Frank", "birthYear": 2000, "age": 24 } ]
🌐 궁극의 도구, $node
객체 활용!
$node
객체는 Code Node 내부에서 워크플로우 실행과 관련된 다양한 정보를 얻고, 심지어는 노드 간에 데이터를 공유할 수 있게 해주는 특별한 전역 객체입니다.
주로 사용되는 속성은 다음과 같습니다.
$node.context
: 🤯 매우 중요! n8n 워크플로우의 실행 간에 데이터를 유지할 수 있는 객체입니다. 예를 들어, 특정 변수의 값을 다음 실행 시에도 기억하고 싶을 때 사용합니다. 워크플로우가 비활성화되거나 n8n 인스턴스가 재시작되면 초기화됩니다.$node.runIndex
: 현재 실행 중인 워크플로우가 몇 번째 실행인지 나타내는 인덱스입니다. 디버깅이나 고유 ID 생성 등에 유용합니다.
예시 4: 워크플로우 실행 횟수 카운트하기 (with $node.context
)
워크플로우가 실행될 때마다 카운트를 증가시키고, 이 카운트 값을 출력 데이터에 추가해 보겠습니다.
-
Code Node 코드:
// $node.context.runCount가 정의되지 않았다면 0으로 초기화합니다. if (!$node.context.runCount) { $node.context.runCount = 0; } // 실행될 때마다 카운트를 1 증가시킵니다. $node.context.runCount++; // 현재 실행 횟수를 콘솔에 출력합니다. console.log(`이 워크플로우는 현재 ${$node.context.runCount}번 실행되었습니다. 📊`); // 모든 출력 아이템에 현재 워크플로우 실행 횟수를 추가합니다. for (const item of items) { item.json.workflowRunCount = $node.context.runCount; } return items;
이 코드는 워크플로우가 실행될 때마다 workflowRunCount
필드의 값이 증가하는 것을 볼 수 있습니다. 이는 A/B 테스트, 사용자 요청 추적, 재시도 횟수 제한 등 다양한 곳에 활용될 수 있습니다. ♾️
🛠️ 오류 처리와 디버깅
Code Node는 코드를 직접 작성하므로, 오류가 발생할 가능성이 있습니다. 효과적인 디버깅은 필수입니다.
-
console.log()
사용:- 가장 기본적인 디버깅 도구입니다. 코드 중간중간
console.log(변수명);
을 넣어 변수의 현재 값을 확인하세요. - 워크플로우를 “Test Run”하면 Output 탭의 “Log” 섹션에서
console.log
출력을 확인할 수 있습니다.
- 가장 기본적인 디버깅 도구입니다. 코드 중간중간
-
try...catch
블록:- 예상치 못한 오류가 발생할 수 있는 코드를
try
블록 안에 넣고,catch
블록에서 오류를 잡아서 처리할 수 있습니다. 이는 워크플로우가 갑자기 멈추는 것을 방지하고, 오류 발생 시 사용자 정의 메시지를 반환하거나 다른 작업을 수행할 수 있게 합니다.
try { // 오류가 발생할 수 있는 코드 const value = item.json.someValue.toUpperCase(); // someValue가 없으면 오류 발생 item.json.processedValue = value; } catch (error) { // 오류가 발생했을 때 처리할 로직 console.error(`아이템 처리 중 오류 발생: ${error.message}`); // 필요하다면, 오류 메시지를 포함한 아이템을 반환하여 다음 노드에서 처리할 수 있게 합니다. item.json.error = `처리 실패: ${error.message}`; }
- 예상치 못한 오류가 발생할 수 있는 코드를
-
Test Run 기능:
- Code Node를 포함한 워크플로우를 “Test Run”하여 실제 데이터가 어떻게 흐르고, 코드의 결과가 어떻게 나오는지 실시간으로 확인하는 것이 가장 중요합니다.
🚀 고급 팁과 트릭
-
비동기 작업 (Async/Await):
- Code Node 내에서 외부 API 호출 등 시간이 필요한 비동기 작업을 수행해야 할 경우,
async/await
문법을 사용할 수 있습니다.
// 주의: 실제 API 호출을 위한 'axios' 등은 npm 설치 후 사용해야 합니다. // 여기서는 개념 설명을 위한 비동기 예시입니다. async function fetchData(url) { return new Promise(resolve => { setTimeout(() => { resolve(`Data from ${url}`); }, 1000); // 1초 지연 }); } const outputItems = []; for (const item of items) { // 각 아이템에 대해 비동기 함수를 기다립니다. const result = await fetchData(item.json.apiUrl); item.json.fetchedData = result; outputItems.push(item); } return outputItems;
- Code Node 내에서 외부 API 호출 등 시간이 필요한 비동기 작업을 수행해야 할 경우,
-
외부 NPM 모듈 사용:
- n8n 인스턴스가 Docker 컨테이너 등으로 실행되는 경우,
npm install
명령어를 통해 필요한 Node.js 모듈을 설치하고 Code Node에서require()
또는import
하여 사용할 수 있습니다. (설정 방법은 n8n 공식 문서를 참조하세요. 일반적인 호스팅 환경에서는 제한될 수 있습니다.)
- n8n 인스턴스가 Docker 컨테이너 등으로 실행되는 경우,
-
함수 분리 및 재사용:
- 코드가 복잡해지면 가독성을 위해 별도의 함수로 분리하여 관리하는 것이 좋습니다.
function calculateDiscount(price, discountRate) { return price * (1 - discountRate); } for (const item of items) { item.json.finalPrice = calculateDiscount(item.json.originalPrice, 0.1); // 10% 할인 } return items;
🚫 Code Node, 언제 사용하지 말아야 할까요?
Code Node는 강력하지만, 항상 최선의 선택은 아닙니다. 다음 경우에는 다른 노드를 사용하는 것이 더 효율적일 수 있습니다.
- 이미 존재하는 n8n 노드가 동일한 기능을 제공할 때: 예를 들어, 단순히 JSON 데이터를 파싱하는 것은 Code Node보다 JSON Node가 훨씬 간단하고 명확합니다. HTTP 요청은 HTTP Request Node를 사용하세요.
- 로직이 너무 복잡해질 때: Code Node의 코드가 수백 줄을 넘어가거나, 유지보수가 어려울 정도로 복잡해진다면, 더 작은 단위로 분리하거나 아예 외부 함수로 빼내는 것을 고려해야 합니다.
- 다른 팀원이 이해하기 어려울 때: Code Node는 코딩 지식이 필요하므로, 코딩을 모르는 팀원이 워크플로우를 이해하고 수정하기 어렵게 만들 수 있습니다. 가능하면 기본 노드로 해결하는 것이 팀 협업에 유리합니다.
마무리하며… 🌟
n8n Code Node는 여러분의 워크플로우 자동화 능력에 날개를 달아줄 강력한 도구입니다. 이 글에서 다룬 기본 개념과 예시들을 바탕으로 직접 워크플로우를 만들어보고 실험해보세요. 처음에는 어려울 수 있지만, 조금씩 코드를 작성하며 익숙해지면 n8n으로 구현할 수 있는 것들의 한계가 사라지는 것을 경험하게 될 것입니다!
궁금한 점이 있다면 n8n 커뮤니티나 공식 문서를 적극 활용하여 질문하고 답을 찾아보세요. 여러분의 멋진 자동화 여정을 응원합니다! 🚀💡✨
Happy Automating!