매일 아침 7시 날씨를 디스코드로 받는 n8n 날씨 알림 — 시트 대신 외부 API를 읽는 첫 워크플로우
이 글과 연결된 글 보기
드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.표시된 글 7편 목록
OpenWeatherMap 무료 API 키 하나와 n8n 노드 5개면, 매일 아침 7시에 서울의 현재 날씨와 앞으로 15시간 예보 표가 디스코드 채널에 도착하는 알림을 만들 수 있습니다. 재고 알림 편에서 구글시트를 읽던 자리에 외부 API가 들어오는 것뿐인데, 이 교체 한 번으로 "API 키를 어디에 두는가"와 "Unix 시각을 한국 시간으로 어떻게 바꾸는가"라는, 모든 API 워크플로우에 따라오는 두 가지를 손에 익히게 됩니다.
이 워크플로우 하나로 보여줄 수 있는 것
재고 알림 편은 "내 시트를 읽어서 조건에 맞으면 알려줘"였습니다. 이 편은 데이터가 내 손에 없습니다. 남의 서버가 가진 데이터를 API로 받아와 내 채널에 맞게 다듬어 보내는 흐름이고, 포트폴리오에 "외부 API 연동 경험"이라고 쓸 수 있는 가장 작은 단위입니다. 안에 들어간 역량은 세 가지입니다.
- 외부 API 호출과 키 관리 — API 키를 노드 안에 적지 않고 n8n credential에 넣어, export하거나 공유해도 키가 따라 나가지 않게 만드는 습관
- 타임스탬프와 시간대 변환 — API가 주는 Unix 초 단위 시각을
Asia/Seoul기준으로 읽을 수 있게 바꾸는 표현식 - 두 응답 합치기 — 현재 날씨와 예보라는 서로 다른 응답을 Merge 노드로 아이템 하나에 모아 메시지 한 통을 만드는 구조
환율, 공공데이터, 서비스 상태 페이지처럼 "정해진 시각에 외부 API를 읽어 알려줘" 유형이라면 이 세 가지에서 URL과 필드 이름만 바뀝니다.
배경 — 출근 전 날씨 앱을 여는 대신
날씨는 매일 확인하지만 매일 잊는 정보입니다. 출근 준비 중에 앱을 열어 우산을 챙길지 정하고, 해가 몇 시에 지는지는 또 따로 찾아봅니다. 이 워크플로우는 그 확인을 "아침 7시에 팀 디스코드 채널에 올라와 있는 메시지 한 통"으로 바꾼 것입니다. 원본 캔버스의 스티키 노트에도 목적이 한 줄로 적혀 있습니다. "openweathermap.org API를 통해 얻어온 날씨 정보를 디스코드에 매일 아침 7시에 발송."
재고 알림 편에서 "Google Sheets 노드 자리에 HTTP Request 노드가 들어간다"고 예고했는데, 실제 원본에는 그 자리에 n8n의 전용 OpenWeatherMap 노드가 들어 있습니다. 이 노드는 겉모습만 다를 뿐 속은 HTTP Request입니다. 내부적으로 /data/2.5/weather와 /data/2.5/forecast를 호출하고, credential의 키를 appid 쿼리 파라미터로 붙여 줍니다. 전용 노드가 있으면 그걸 쓰고 없을 때 HTTP Request를 직접 쓰는데, 원본 캔버스에는 직접 부른 테스트 흔적도 남아 있어 두 방식을 나란히 볼 수 있습니다.
설치나 기본 노드 설명은 n8n으로 반복업무 자동화 포트폴리오 만들기에 있으니, 이 글에서는 워크플로우 자체만 다룹니다.
OpenWeatherMap 가격 페이지 기준(2026년 8월)으로 무료 플랜은 분당 60회, 월 1,000,000회까지 호출할 수 있고, 이 워크플로우가 쓰는 Current Weather API와 3시간 간격 5일 예보(3-hour Forecast 5 days)가 둘 다 포함됩니다. 회원가입 후 API keys 메뉴에서 키를 발급받으면 됩니다. One Call 계열 API는 무료 플랜 목록에 없고 별도의 호출당 과금 구독인데, 이 글의 본 흐름에는 필요 없습니다.
구조 — Trigger / Task / Target
데이터팝콘은 워크플로우를 언제 시작하는가(Trigger), 무엇을 하는가(Task), 어디로 보내는가(Target) 세 칸으로 나눠 봅니다. 이 워크플로우는 트리거 하나에서 두 갈래가 나뉩니다.
- Trigger — 매일 아침 7시 스케줄
- Task — 현재 날씨와 5일 예보를 각각 받기 → 한국 시간으로 변환 → 메시지 문자열 조립 (선택: Merge로 두 응답을 아이템 하나로 합치기)
- Target — 디스코드 웹훅 채널 두 통, 또는 Merge를 거친 슬랙 한 통
디스코드 갈래가 원본의 본 흐름이고, Merge → Slack 갈래는 두 응답을 하나로 합치는 패턴을 보여주는 확장이라 마지막에 같이 다룹니다.
만들기
0. API 키는 credential에 넣기
n8n의 Credentials 메뉴에서 OpenWeatherMap API를 추가하고 발급받은 키를 Access Token 칸에 붙여 넣습니다. 이후 OpenWeatherMap 노드는 이 credential을 고르기만 하면 되고, 키는 워크플로우 JSON 어디에도 남지 않습니다.
이걸 첫 단계로 둔 이유는 원본 캔버스에 반대 예시가 남아 있기 때문입니다. Set 노드에 app_id 필드로 키를 넣고 HTTP Request URL에 appid={{ $json.app_id }}로 이어 붙인 테스트 흐름인데, 이렇게 만들면 export한 JSON 파일에 키가 그대로 박힙니다. 공개할 워크플로우라면 이 차이가 곧 평가 포인트입니다.
1. Schedule Trigger — 매일 아침 7시
Schedule Trigger 노드에서 Trigger Interval을 Days, Trigger at Hour를 7로 둡니다. 스케줄은 워크플로우 Settings의 Timezone을 따르므로 Asia/Seoul로 되어 있는지 확인해 두세요. 실습 중에는 Execute workflow 버튼으로 바로 돌려보고, 마지막에 Active를 켜면 그때부터 매일 7시에 돕니다.
2. OpenWeatherMap 노드 두 개 — 현재 날씨와 5일 예보
트리거 뒤에 OpenWeatherMap 노드를 두 개 나란히 붙입니다. 둘 다 Location Selection은 City Name, City는 seoul, Language는 kr이고, 하나는 Operation을 Current Weather로, 다른 하나는 5 Day Forecast로 둡니다. Format은 기본값 Metric이라 기온이 섭씨로 오고, Language가 kr이라 날씨 설명이 한국어로 옵니다.
실행하고 출력 패널에서 응답 모양을 확인해 두세요. 다음 노드의 표현식이 이 필드 이름을 씁니다.
- 현재 날씨:
main.temp(기온),main.feels_like(체감),weather[0].description(날씨 설명),sys.sunrise·sys.sunset(일출·일몰),dt(관측 시각) - 5일 예보:
list배열에 3시간 간격 항목이 들어 있고, 항목마다dt,main.temp,weather[0].description이 있습니다
시각 필드는 전부 Unix 초 단위 숫자라 그대로 보내면 아무도 못 읽습니다. 다음 단계의 표현식이 이걸 한국 시간으로 바꿉니다.
3. Discord — 웹훅으로 현재 날씨 보내기
디스코드 채널 설정의 연동(Integrations) 메뉴에서 웹훅을 만들고 URL을 복사한 뒤 n8n에 Discord Webhook credential로 저장합니다. Discord 노드에서 Connection Type을 Webhook으로 두고 그 credential을 고르면 됩니다. 웹훅 URL도 키와 마찬가지로 노드 안에 직접 적지 않습니다.
Message의 Content에는 원본 표현식을 그대로 넣습니다.
⏰ {{ $json.dt.toDateTime('s').setZone('Asia/Seoul').format('LLL dd yyyy, HH:mm:dd') }} 기준
현재 서울은 "{{ $json.weather[0].description }}" 입니다.
현재 기온은 {{ $json.main.temp }}'C (체감 온도 {{ $json.main.feels_like }}'C)
🌅일출시각 : {{ $json.sys.sunrise.toDateTime('s').setZone('Asia/Seoul').format('HH:mm:dd') }}
🌇일몰시각 : {{ $json.sys.sunset.toDateTime('s').setZone('Asia/Seoul').format('HH:mm:dd') }}
핵심은 toDateTime('s').setZone('Asia/Seoul').format(...) 세 단계입니다. toDateTime('s')가 초 단위 Unix 숫자를 날짜 객체로 만들고, setZone('Asia/Seoul')이 시간대를 한국으로 옮기고, format()이 읽을 수 있는 문자열로 바꿉니다. API에서 받은 시각을 다룰 때는 이 세 단계를 한 묶음으로 기억해 두세요.
다만 복사해 쓸 때 두 군데는 고치는 게 좋습니다. 원본의 HH:mm:dd에서 dd는 초가 아니라 "일(day)"이라, 일출 시각이 06:12:17처럼 나오면 끝의 17은 17일이라는 뜻입니다. HH:mm으로 바꾸면 되고, 기온 뒤의 'C도 °C로 바꾸는 편이 읽기 좋습니다.
4. Discord — 예보 표 보내기
5일 예보 노드 뒤에는 Discord 노드를 하나 더 붙이고 Content에 표를 조립합니다. 디스코드는 마크다운 표를 그려주지 않아서 원본은 코드 블록 안에 파이프로 구분한 텍스트 표를 넣었습니다. list[2]부터 list[4]까지 같은 형식으로 세 줄이 더 있습니다.
```
| 날짜 및 시간 | 날씨 상태 | 기온 ('C) |
| {{ $json.list[0].dt.toDateTime('s').setZone('Asia/Seoul').format('yyyy-MM-dd T') }} | {{ $json.list[0].weather[0].description }} | {{ $json.list[0].main.temp }} |
| {{ $json.list[1].dt.toDateTime('s').setZone('Asia/Seoul').format('yyyy-MM-dd T') }} | {{ $json.list[1].weather[0].description }} | {{ $json.list[1].main.temp }} |
```
list[0]부터 list[4]까지 다섯 줄이므로 3시간 간격 기준 앞으로 약 15시간치가 표에 들어갑니다. format('yyyy-MM-dd T')의 T는 시각을 09:00 같은 24시간 표기로 찍는 토큰입니다. 두 Discord 노드를 실행해 채널에 메시지가 두 통 도착하면 본 흐름은 완성입니다.
5. (선택) Merge → Slack — 두 응답을 한 통으로
디스코드 갈래는 현재 날씨와 예보가 두 통으로 나뉘어 옵니다. 원본 캔버스에는 이걸 한 통으로 합친 슬랙 갈래가 같이 있습니다. 현재 날씨 노드와 예보 노드의 출력을 Merge 노드의 입력 1, 2에 각각 연결하고 Mode를 Combine, Combine By를 Position으로 두면 두 노드의 첫 아이템이 하나로 합쳐집니다. 결과 아이템에 main.temp와 list가 같이 들어 있으니, 뒤의 Slack 노드(Message Type: Blocks, 채널 선택) 하나에서 위의 두 표현식을 한 메시지에 쓸 수 있습니다.
재고 편의 Code 노드가 여러 행을 문자열 하나로 합쳤다면, 여기서는 Merge 노드가 서로 다른 출처의 아이템을 필드 단위로 합칩니다.
원본 캔버스에 남아 있는 흔적 — 키를 어디에 두느냐의 차이
이 워크플로우는 교육용이라 운영 데이터는 없습니다. 대신 캔버스에 본 흐름과 연결되지 않은 노드가 여럿 떠 있고 스티키 노트가 용도를 적어 두고 있어서 그걸 옮깁니다.
첫째는 "API 테스트 — 본인의 API_KEY를 입력 후 실행"이라는 스티키 아래의 Set → HTTP Request 두 노드입니다. HTTP Request가 One Call 3.0 API의 timemachine 엔드포인트를 위도·경도와 appid={{ $json.app_id }}로 호출합니다. 전용 노드 없이 API를 부를 때의 뼈대인데, 키가 Set 노드에 있다는 점과 One Call 계열은 무료 플랜 밖이라는 점을 짚어 둘 만합니다. 지금 만든다면 HTTP Request 노드의 Authentication을 Generic Credential Type → Query Auth로 두고 appid를 credential에 저장하면 URL에 키를 이어 붙일 필요가 없습니다.
둘째는 "모바일, 크롬 푸시 알림 — 앱 설치 후 연동"이라는 스티키 아래의 Pushbullet·Pushover 노드입니다. 메시지 표현식이 디스코드 노드와 완전히 같아서, Target만 바꾸면 되는 구조라는 것을 캔버스가 보여줍니다.
셋째는 작은 흔적 두 개입니다. 현재 날씨를 보내는 Discord 노드 이름이 "날씨 예보 발송", 예보 표를 보내는 노드가 "현재 날씨 발송"으로 서로 바뀌어 있습니다. 실행에는 영향이 없지만 노드 이름은 하는 일 그대로 붙이는 게 좋습니다. 그리고 슬랙 갈래에서는 HH:mm:dd가 HH:mm:ss로, 'C가 °C로 고쳐져 있어, 디스코드 버전을 먼저 만들고 슬랙 버전에서 다듬은 순서가 남아 있습니다.
한계
- 예보 범위가 짧습니다 —
list[0]~list[4]는 앞으로 15시간이라 "내일 날씨"는 없습니다. 같은 폴더의 다른 버전에서는list[7](약 21시간 뒤)을 "tomorrow"로 뽑아 둔 흔적이 있으니, 원하는 시점의 인덱스를 골라 쓰면 됩니다. - 도시가 고정입니다 —
seoul이 노드에 박혀 있습니다. 여러 도시를 돌리려면 도시 목록 아이템을 만들어 City에{{ $json.city }}처럼 표현식으로 넣어야 합니다. - 실패하면 조용히 멈춥니다 — 키가 만료되거나 응답이 비면 메시지가 안 올 뿐 아무도 모릅니다. Error Trigger 편에서 따로 다룹니다.
- 메시지 길이 — 디스코드 웹훅 메시지 본문은 2,000자까지입니다. 예보를 늘리거나 여러 도시를 한 통에 넣으면 이 한도에 걸릴 수 있습니다.
포트폴리오·면접 포인트
포트폴리오에는 캔버스 스크린샷, 디스코드에 도착한 메시지 캡처, 키를 가린 credential 설정 화면 세 장이 좋습니다. 세 번째가 있으면 "키를 어디에 뒀는지"를 말하지 않아도 보여줄 수 있습니다.
응용은 두 방향이 자연스럽습니다. 하나는 재고 편의 Filter를 가져와 비나 눈 예보가 있는 날만 보내는 것입니다. 다른 하나는 같은 무료 플랜에 포함된 Air Pollution API로 미세먼지를 같은 메시지에 붙이는 것인데, OpenWeatherMap 노드에 없는 API라 HTTP Request + Query Auth credential을 직접 써 보는 연습이 됩니다.
면접에서는 "API 키를 왜 credential에 넣었나요?"나 "시각이 왜 9시간 어긋났나요?" 같은 질문이 올 수 있습니다. 앞의 답은 export와 공유 시 키 노출을 막기 위해서, 뒤의 답은 API가 UTC 기준 Unix 초를 주기 때문에 setZone으로 시간대를 옮겨야 한다는 것입니다. 둘 다 외부 시스템의 데이터를 내 환경으로 가져올 때 무엇이 달라지는지 이해했다는 답입니다.
다음 액션
여기까지 만들면 "정해진 시각에 외부 API를 읽어 채널로 보낸다"는 틀이 손에 익습니다. 다음 편은 API 대신 RSS를 읽습니다. 뉴스 RSS 피드 5개를 모아 매일 메일 한 통으로 보내는 워크플로우인데, 소스가 여러 개일 때 아이템을 어떻게 모으는지를 다룹니다. 그다음에 이 편의 한계에서 미룬 Error Trigger 편으로 넘어갑니다.
