학교코드만 바꾸면 재사용 — n8n 워크플로우를 일회성 스크립트에서 템플릿으로 만드는 법
이 글과 연결된 글 보기
드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.표시된 글 8편 목록
학교코드·슬랙 채널만 바꾸면 다른 학교에서도 그대로 쓸 수 있는 급식 알림 워크플로우를 보면, 한 번 쓰고 버리는 스크립트를 재사용 가능한 템플릿으로 만드는 법을 알 수 있습니다. 바꿔야 할 값 여섯 개를 Set 노드 하나에 모으고, 뒤에 오는 노드들이 전부 그 노드를 이름으로 참조하게 만들면 됩니다.
이 워크플로우 하나로 보여줄 수 있는 것
지금까지 만든 워크플로우는 대부분 상황 하나에 맞춰져 있었습니다. 이 워크플로우는 처음부터 "다른 상황에서도 쓸 수 있게" 설계돼 있다는 점이 다릅니다. 면접에서 "재사용 가능하게 설계한 적 있나요?"라는 질문에 구체적으로 답할 수 있는 근거가 됩니다.
- 설정값 집중 설계 — 바꿔야 할 값 여섯 개를 노드 하나에 모아본 경험
- 노드 이름으로 참조하기 — 하드코딩 대신 설정 노드를 가리키게 만들어본 경험
- 날짜 자동 계산 — "오늘"을 표현식으로 매번 새로 만들어본 경험
- 방어적 분기 — 데이터가 없는 날을 에러가 아니라 정상 상황으로 처리해본 경험
네 가지 전부 이 워크플로우 하나에, 노드 다섯 개짜리 짧은 구조 안에 들어 있습니다.
배경 — API 자체가 아니라 재사용 설계를 다룹니다
이전 편인 급식 API로 배우는 n8n 페이지네이션에서는 NEIS 급식식단정보 API 자체를 다뤘습니다. 한 번에 다 안 주는 응답을 페이지를 넘겨가며 끝까지 받는 방법이었습니다. 이번 워크플로우는 같은 API를 쓰지만 목적이 다릅니다. 학교 하나의 오늘 급식만 매일 아침 받는, 훨씬 단순한 구조입니다. 이 워크플로우가 보여주는 건 API 자체가 아니라 한 번 만든 워크플로우를 다른 상황에서도 쓸 수 있게 만드는 법입니다.
이 워크플로우에는 스티키 노트가 하나도 없습니다. 만든 사람이 남긴 설계 의도는 워크플로우 자체의 description 필드 한 줄이 전부입니다. "플래그십 자동화 레시피. 학교코드/채널만 바꾸면 어느 학교든 사용 가능"이라고 적혀 있습니다. 이 한 줄이 이 편의 출발점입니다. 설치나 HTTP Request 노드 기본은 n8n으로 반복업무 자동화 포트폴리오 만들기에서 다뤘으니, 여기서는 재사용 설계만 봅니다.
구조 — Trigger / Task / Target
- Trigger — 매일 07:00 스케줄
- Task — 설정값 조회 → NEIS API 호출 → 응답 파싱과 메시지 조립
- Target — 슬랙 채널. Slack 노드는 이 채널 값도 시트나 API가 아니라 Set 노드에서 그대로 가져옵니다
만들기
1. Set 노드 — 바꿔야 할 값 여섯 개를 한곳에
"급식 조회 설정"이라는 이름의 Set(Edit Fields) 노드에 필드 여섯 개가 들어 있습니다.
officeCode:B10(시도교육청 코드)schoolCode:7010083(학교 코드)schoolName:서울고등학교mealCode:2(급식 종류를 지정하는 값)targetDate: 표현식 — 아래에서 따로 설명합니다slackChannel: 실제 채널 ID를 넣을 자리
officeCode·schoolCode·schoolName은 이 템플릿에 기본값으로 박아 둔 예시 학교일 뿐입니다. 학교 코드는 시도교육청·학교마다 공개된 값이라 그대로 보여줘도 문제없지만, 이 학교가 데이터팝콘과 관련 있다는 뜻은 아닙니다. 학교 코드는 NEIS 학교기본정보 API(schoolInfo)로 원하는 학교를 검색해 받을 수 있습니다. slackChannel에는 실제 값 대신 채널 ID를 넣어야 한다는 자리표시자가 들어 있고, 워크플로우를 다른 워크스페이스에서 쓰려면 봇을 그 채널에 먼저 초대해야 합니다.
이 여섯 개 값이 이 워크플로우를 플래그십이라고 부를 만한 이유입니다. 다른 학교로 옮기고 싶으면 이 Set 노드 하나만 열면 됩니다. HTTP Request, Code, Slack 노드는 전혀 건드릴 필요가 없는데, 그 이유는 다음 단계에 있습니다.
2. 뒤 노드들이 노드 이름으로 값을 가져오는 이유
NEIS 급식 조회 노드는 Set 노드 바로 다음이라 이런 표현식을 씁니다.
ATPT_OFCDC_SC_CODE:{{ $json.officeCode }}SD_SCHUL_CODE:{{ $json.schoolCode }}MLSV_YMD:{{ $json.targetDate }}
$json이 곧 Set 노드의 출력이라서 직접 참조해도 됩니다. 하지만 그 뒤 Code 노드와 Slack 노드는 사정이 다릅니다. Code 노드에 들어올 때는 $json이 이미 HTTP Request의 응답으로 바뀌어 있어서, officeCode나 schoolName 같은 원래 설정값은 $json으로 더는 안 잡힙니다. 그래서 Code 노드는 이렇게 씁니다.
const cfg = $('급식 조회 설정').first().json;
const school = cfg.schoolName || '';
Slack 노드의 채널 필드도 같은 방식입니다.
{{ $("급식 조회 설정").first().json.slackChannel }}
노드 이름(급식 조회 설정)으로 직접 가리키면, 그 사이에 노드가 몇 개 더 지나가도 원래 값을 그대로 꺼낼 수 있습니다. $json으로만 체이닝했다면 노드가 하나 늘어날 때마다 값을 넘겨받는 필드를 다시 손봐야 했을 겁니다. n8n-expressions 스킬에서도 여러 단계 뒤까지 값을 들고 가야 할 때는 노드 이름 참조를 권합니다.
3. targetDate — 매번 다시 계산되는 "오늘"
{{ $now.setZone("Asia/Seoul").toFormat("yyyyLLdd") }}
이 값은 저장된 날짜가 아니라 실행될 때마다 계산되는 식입니다. $now는 워크플로우가 실행되는 순간의 시각이고, setZone("Asia/Seoul")로 한국 시간대에 맞춘 다음, toFormat("yyyyLLdd")로 NEIS가 요구하는 YYYYMMDD 형식 문자열을 만듭니다. 매일 07:00 트리거가 실행될 때마다 이 필드는 그날 날짜로 새로 계산됩니다. Set 노드에 날짜를 문자열로 박아뒀다면 이 워크플로우는 만든 날 하루만 맞게 동작하고, 다음 날부터는 계속 어제 날짜를 조회하게 됩니다.
4. Code 노드 — 급식 없는 날을 에러로 만들지 않기
메뉴 포맷 노드는 파싱과 "급식 없는 날" 처리를 한 노드 안에서 같이 합니다.
let rows = [];
const info = res.mealServiceDietInfo;
if (Array.isArray(info)) {
const rowBlock = info.find(b => Array.isArray(b.row));
rows = rowBlock ? rowBlock.row : [];
}
let text;
if (rows.length === 0) {
text = `🍚 *${school} 급식 (${dateLabel})*\n오늘은 등록된 급식이 없습니다. (주말·공휴일이거나 아직 미등록)`;
} else {
// rows를 순회하며 메뉴 문자열을 슬랙 메시지로 조립
}
별도의 If 노드로 "데이터가 있다/없다"를 가르지 않고, rows.length가 0인지만 코드 안에서 확인합니다. 응답이 예상과 다른 모양이어도(info가 배열이 아니면) rows는 그냥 빈 배열로 시작하기 때문에, 이 분기가 "데이터 없음"과 "예상과 다른 응답"을 같은 방식으로 처리합니다. HTTP Request 노드의 응답 옵션에도 neverError가 켜져 있어서, NEIS가 무엇을 돌려주든 이 Code 노드까지 넘어옵니다.
메뉴가 있는 경우에는 DDISH_NM 필드 하나에 메뉴 여러 개가 `<br/>` 태그로 이어져 옵니다. 정규식으로 줄바꿈으로 바꾸고 괄호 표시를 정리한 다음, 글머리 기호를 붙여 슬랙 메시지로 조립합니다. 급식 종류 이름은 계산하지 않고 API 응답의 MMEAL_SC_NM 필드를 그대로 씁니다.
원본 캔버스에 남아 있는 흔적
이 워크플로우에는 스티키 노트가 없어서, 설계 의도를 읽으려면 노드 구조 자체를 봐야 합니다.
가장 먼저 눈에 띄는 게 Set 노드의 필드 이름입니다. NEIS API가 실제로 요구하는 파라미터 이름은 ATPT_OFCDC_SC_CODE, SD_SCHUL_CODE처럼 대문자와 밑줄로 된 이름인데, Set 노드의 필드는 officeCode, schoolCode처럼 사람이 읽기 편한 이름을 새로 붙였습니다. 이름을 새로 붙인 것 자체가, 이 워크플로우를 나중에 다른 사람이나 다른 학교로 넘길 걸 염두에 두고 만들었다는 흔적입니다.
또 하나는 HTTP Request 노드의 neverError 옵션과 Code 노드의 rows.length 분기가 짝을 이룬다는 점입니다. 에러를 에러로 멈추게 하는 대신, 무엇이 오든 일단 Code 노드가 받아 "데이터가 있으면 메뉴로, 없으면 안내 메시지로" 정리하게 만들었습니다. 스티키 노트가 없어도, 이 두 설정이 나란히 있는 걸 보면 우연이 아니라 의도된 조합이라는 걸 알 수 있습니다.
한계
- 슬랙 채널 값이 자리표시자 — 실제로 쓰려면 채널 ID를 직접 넣고, 봇을 그 채널에 먼저 초대해야 합니다.
- 인증키가 없음 — Set 노드에 API 키 필드가 아예 없습니다. 이전 편(페이지네이션)은 여러 학교, 여러 페이지를 반복 호출하느라 인증키가 필요했지만, 이 워크플로우는 하루에 학교 하나, 호출 한 번뿐입니다. 호출 빈도가 늘어난다면 이전 편에서 다룬 credential 방식으로 옮기는 게 안전합니다.
- 급식 없음과 응답 이상이 구분되지 않음 — Code 노드는 데이터가 없는 것과 응답 형태가 예상과 다른 것을 같은 메시지로 처리합니다. API 자체가 며칠 죽어 있어도 매일 아침 "오늘은 급식이 없습니다"라는 조용한 메시지만 오게 되어 실제 장애를 알아차리기 어렵습니다.
- 학교 하나, 채널 하나 — Set 노드가 값을 하나씩만 담고 있어서, 여러 학교를 한 번에 보내려면 이 구조 위에 반복(Loop Over Items 등)을 얹어야 합니다.
포트폴리오·면접 포인트
"새 학교로 이 워크플로우를 재사용하려면 Set 노드 값 6개만 바꾸면 된다"는 걸 직접 해보는 걸 권합니다. 관심 있는 학교의 코드를 NEIS 학교기본정보 API로 찾아 officeCode·schoolCode·schoolName을 바꾸고, 알림 받을 채널로 slackChannel을 바꾸면 끝입니다. HTTP Request, Code, Slack 노드는 하나도 열지 않아도 됩니다. 실제로 다른 학교 급식이 오는 걸 캡처해두면, "재사용 가능하게 설계했다"는 포트폴리오 문장의 증거가 됩니다.
면접에서 "재사용 가능하게 만들었다는 게 무슨 뜻인가요?"가 오면, 바꿔야 할 값을 노드 하나에 모으고 뒤 노드들이 그 노드를 이름으로 참조하게 만들어서 코드나 다른 노드를 건드릴 필요가 없게 했다고 답하면 됩니다. "왜 그렇게 설계했나요?"가 이어지면, 값이 여러 노드에 흩어져 있으면 바꿀 곳을 하나씩 찾아야 하고 빠뜨리기 쉽지만, 한곳에 모아두면 그 노드만 확인하면 된다고 답하면 됩니다.
다음 액션
이 워크플로우는 슬랙으로 메시지 하나를 보내는 데서 끝납니다. 다음 편은 한 걸음 더 나가서, 시트에 쌓아둔 데이터를 인스타그램 카드뉴스로 발행까지 잇는 워크플로우입니다. 알림 하나를 보내는 것과 이미지를 만들어 발행하는 것은 고려할 게 꽤 다른데, 그 차이를 다음 편에서 확인할 수 있습니다.
