날씨요정 개발기: OpenWeather API로 실시간 날씨 웹앱 만들기
OpenWeather API를 활용하여 현재 날씨를 분석하고 산책하기 좋은 날씨인지 알려주는 웹앱을 개발한 과정입니다.
프로젝트 배경
"오늘 산책하기 좋은 날씨일까?"라는 단순한 궁금증에서 시작된 프로젝트입니다. 기존 날씨 앱들은 온도, 습도, 풍속 같은 수치를 나열하지만, 그 숫자들이 실제로 어떤 느낌인지 직관적으로 알려주지 않습니다.
체감 온도, 습도, 바람 세기를 종합적으로 분석해서 "지금 밖에 나가면 어떤 기분일지"를 친근하게 알려주는 앱을 만들고 싶었습니다.
기술 구성
OpenWeather API 선택 이유
무료 날씨 API 중에서 OpenWeather를 선택한 이유는 다음과 같습니다:
- 무료 티어로 충분: 월 1,000회 호출이 무료이고, 개인 프로젝트에는 넉넉합니다
- 데이터 풍부: 현재 날씨, 체감 온도, 습도, 풍속, 구름량, 일출/일몰 시간 등 다양한 데이터 제공
- 한국어 지원: 날씨 설명이 한국어로 제공됩니다
프로젝트 구조
app/
├── page.tsx # 메인 페이지 (위치 입력 + 결과)
├── layout.tsx # 레이아웃
└── api/
└── weather/
└── route.ts # API 프록시 (API 키 보호)
API 키를 클라이언트에 노출하지 않기 위해, Next.js API Route를 프록시로 활용했습니다. 클라이언트는 /api/weather?city=Seoul로 요청하고, 서버에서 API 키를 붙여 OpenWeather에 전달합니다.
핵심 기능: 날씨 쾌적도 분석
단순히 날씨 데이터를 보여주는 것이 아니라, 여러 요소를 종합해서 "산책 지수"를 계산합니다.
쾌적도 판단 기준
| 요소 | 좋음 | 보통 | 나쁨 | |------|------|------|------| | 체감 온도 | 15~25°C | 5~15°C, 25~30°C | 5°C 미만, 30°C 초과 | | 습도 | 40~60% | 30~40%, 60~70% | 30% 미만, 70% 초과 | | 풍속 | 0~3m/s | 3~7m/s | 7m/s 초과 | | 강수 | 없음 | 약한 비 | 비/눈 |
각 요소별 점수를 매기고 가중 평균으로 최종 쾌적도를 산출합니다. 이 쾌적도에 따라 "날씨요정"이 다른 메시지를 보여줍니다.
UI 디자인 과정
감성적인 날씨 표현
날씨 상태에 따라 배경 그라데이션이 바뀌도록 설계했습니다:
- 맑은 날: 하늘색에서 흰색으로 부드러운 그라데이션
- 흐린 날: 회색 톤의 차분한 배경
- 비 오는 날: 진한 남색 배경
- 눈 오는 날: 밝은 회백색 배경
요정 캐릭터 메시지
날씨 데이터를 딱딱한 숫자로만 보여주면 재미가 없습니다. 그래서 "날씨요정" 컨셉으로 친근한 메시지를 추가했습니다:
- 쾌적도 높음: "밖에 나가면 기분이 좋아질 거예요! 산책하기 딱 좋은 날이에요."
- 쾌적도 보통: "나쁘지 않은 날씨예요. 가벼운 겉옷 하나 챙기면 좋겠어요."
- 쾌적도 낮음: "오늘은 집에서 쉬는 것도 좋은 선택이에요."
개발 중 만난 문제들
위치 정보 권한
navigator.geolocation으로 사용자 위치를 자동 감지하는 기능을 넣었는데, 많은 사용자가 위치 권한을 거부합니다. 그래서 도시명 직접 입력도 함께 지원하도록 했습니다.
API 호출 최적화
날씨 데이터는 실시간이지만, 1분마다 바뀌지는 않습니다. 같은 위치로 반복 요청하는 것을 방지하기 위해, 마지막 조회 시간으로부터 10분 이내면 캐시된 데이터를 보여주도록 구현했습니다.
한글 도시명 처리
OpenWeather API는 영문 도시명을 기본으로 사용합니다. 사용자가 "서울"이라고 입력했을 때 "Seoul"로 변환해주는 매핑 테이블을 만들었습니다. 주요 도시들은 한글-영문 매핑을 해놓고, 매핑에 없는 경우 영문 입력을 안내합니다.
결과와 피드백
Vercel에 배포한 후 주변에 공유했을 때, "귀엽다"는 반응이 가장 많았습니다. 날씨 앱치고는 감성적이라는 평가였습니다. 특히 "산책 지수" 기능이 실용적이라는 피드백을 받았습니다.
앞으로 시간별 날씨 예보와 주간 예보 기능을 추가할 예정입니다. 또한 날씨에 따른 옷차림 추천 기능도 고려하고 있습니다.