03. 남의 기술 가져다 쓰기 (Import)
"코딩(How)은 AI가 합니다. 우리는 주문서(What)만 정확히 작성하면 됩니다."
2부에서 배운 React를 사용해서 실제 세상의 살아있는 데이터를 가져와 봅시다. 단순히 데이터를 가져오는 것을 넘어, "남의 지능(AI)"을 내 서비스로 수입(Import)하는 경험을 할 것입니다.
1. API의 4가지 필수 재료 (Ingredients)
AI에게 요리(코딩)를 시키려면, 우리가 먼저 장을 봐와야 합니다. API 문서(메뉴판)를 보고 딱 4가지만 찾아내세요.
| 재료 | 개발 용어 | 설명 | 비유 (식당/배달) |
|---|---|---|---|
| 1. 주소 | Endpoint (URL) | 어디로 요청할 것인가? | 식당 위치 (https://api.weather.com) |
| 2. 방법 | Method | 무엇을 할 것인가? | 주문(GET) vs 예약(POST) vs 취소(DELETE) |
| 3. 열쇠 | Auth (API Key) | 입장권이 필요한가? | VIP 회원권 (없으면 문전박대) |
| 4. 옵션 | Parameter | 구체적으로 무엇을 원하는가? | "서울 날씨, 섭씨(C)로, 내일 것만 줘" |
💡 Tip
보통 ? 뒤에 붙는 것이 Parameter(옵션)입니다.
예: search?query=아이폰&sort=price (아이폰을 검색하고, 가격순으로 정렬해줘)
2. The 4 Basic Moves: CRUD (할 수 있는 일)
API를 사용할 때 우리가 할 수 있는 행동은 딱 4가지뿐입니다.
| 행동 | 영어 (CRUD) | Method | 비유 (SNS) |
|---|---|---|---|
| 만들기 | Create | POST |
인스타그램 사진 업로드 |
| 읽기 | Read | GET |
피드 구경하기 (가장 많이 함) |
| 고치기 | Update | PUT |
오타 수정하기 |
| 지우기 | Delete | DELETE |
흑역사 삭제하기 |
3. Level 1. 연습용 API: 가짜 데이터 수입하기 🟢
처음부터 복잡한 열쇠(Key)를 다루면 머리가 아픕니다. 먼저 전 세계 개발자들의 연습장인 JSON Placeholder를 사용해서, "가짜 블로그 글 100개"를 가져오는 연습을 해봅시다. 이곳은 열쇠 없이 누구나 들어갈 수 있는 무료 급식소 같은 곳입니다.
AI Native Workflow
여러분이 할 일은 코딩이 아닙니다. '정확한 작업 지시서'를 만드는 것입니다.
Step 1: 재료 수집 (From Docs)
- URL:
https://jsonplaceholder.typicode.com/posts- Method:
GET(글 목록 조회)- Key: 없음 (누구나 사용 가능!)
- Data:
userId,id,title(제목),body(내용)으로 구성됨.
Step 2: AI에게 주문 (To AI)
Prompt
위의 연습용 API(jsonplaceholder)를 이용해서 '블로그 포스트 목록'을 보여주는 React 컴포넌트를 만들어줘.
axios를 사용해서 데이터를 가져와.- 데이터가 오는 동안 '로딩 중...' 메시지를 띄우고, 실패하면 에러 메시지를 보여줘. (필수!)
- 글이 100개나 되니까 상위 5개만 잘라서 보여줘 (
slice사용). - 각 글은 제목(
h3)과 내용(p)이 있는 카드 형태로 예쁘게 디자인해줘.
Step 3: 도착할 데이터 미리보기 (Expectation) AI가 코드를 짜주면, 브라우저 콘솔에는 이런 리스트(Array) 형태의 데이터가 도착할 것입니다.
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere...",
"body": "quia et suscipit..."
},
{ ... },
{ ... }
]
성공 포인트
화면에 알 수 없는 라틴어(Lorem Ipsum)로 된 글 5개가 카드 모양으로 떴다면 성공입니다! 이제 여러분은 "남의 서버에 있는 데이터를 내 화면으로 가져오는 기술"을 익혔습니다.
4. Level 2. AI API: 지능 수입하기 (Gemini) 🤖
이것이 4부의 핵심입니다. 우리는 단순히 날씨나 주가를 가져오는 걸 넘어, "생각하는 뇌"를 빌려올 수 있습니다. 구글의 Gemini에게 복잡한 일을 시키는 버튼을 만들어봅시다.
Step 1: 천재 직원 채용하기 (API Key 발급) 🔑
코드를 짜기 전에, 먼저 구글에게 가서 "당신의 AI를 쓰고 싶습니다"라고 허락을 받아야 합니다.
- 접속: Google AI Studio에 접속해서 구글 아이디로 로그인합니다.
- 발급: 왼쪽 하단의
Get API key버튼 -> 오른쪽 상단의Create API key를 클릭하고 절차를 따라가세요. - 복사:
AIzaSy...로 시작하는 긴 암호가 나옵니다. 이 키를 복사(복사버튼 클릭) 하세요.
Step 2: 비밀 금고에 보관하기 (.env 설정) 🔒
방금 복사한 키를 코드 파일(.js)에 그대로 적으면 해커들의 먹잇감이 됩니다.
환경 변수(Environment Variable)라는 비밀 금고에 숨겨야 합니다.
- 생성: VS Code 왼쪽 파일 탐색기에서 우클릭 ->
New File-> 파일명을.env로 만듭니다. (점 하나, env 세 글자) - 저장: 파일 안에 다음과 같이 적고 키를 붙여넣습니다.
- 자동 재시동:
- Vite(
npm run dev)는.env파일이 바뀌면 알아서 감지하고 서버를 재시작해 줍니다. 똑똑하죠? - (혹시라도 적용이 안 된다면, 터미널에서
Ctrl + C로 껐다가 다시 켜보세요.)
- Vite(
GitHub에 올리기 전에 확인하세요!
.gitignore 파일에 .env가 적혀 있는지 꼭 확인하세요.
이 파일은 "내 금고는 GitHub에 올리지 마!"라고 경비원(Git)에게 말해주는 명단입니다.
(보통 React를 설치하면 기본으로 적혀 있습니다.)
"그럼 배포할 땐 어떻게 해요?"
배포할 때는 이 .env 파일을 서버에 업로드하는 게 아니라, 배포 사이트의 설정 메뉴에 따로 입력해야 합니다.
자세한 방법은 [6부. 세상 밖으로 (Deployment)]에서 다룹니다. 지금은 내 컴퓨터에서 안전하게 돌리는 것에 집중합시다!
Step 3: 차이점 이해하기 (일반 vs AI)
- 일반 API: "삼성전자 주가 얼마야?" -> "7만원." (정해진 팩트)
- AI API: "이 기사 3줄 요약해줘." -> (생각 중...) -> "1. 핵심은... 2. 내용은... 3. 결론은..." (창조된 지능)
Step 4: 실습 - 'AI 요약 버튼' 만들기 🚀
이제 안전하게 저장된 키를 꺼내서 사용해봅시다.
💡 Tip
사용 가능한 최신 모델(gemini-3-flash-preview 등) 정보는 Gemini API 공식 문서에서 확인할 수 있습니다.
Prompt
Google Gemini API를 사용해서 기능을 만들고 싶어.
- API Key는 내가
.env에VITE_GEMINI_KEY라고 저장했어. (import.meta.env로 가져와줘) - 화면에 긴 글을 입력할
textarea와 '요약하기' 버튼을 만들어줘. - 버튼을 누르면
axios를 사용해 Gemini API로 텍스트를 보내. (모델은gemini-2.5-flash사용) - 응답받은 요약문을 버튼 아래에 예쁘게 보여줘.
이렇게 하면 여러분은 단 10분 만에 "AI 기반 서비스"를 런칭한 개발자가 됩니다.
5. 🕹️ 종합 실습: '전천후 날씨 위젯' 시스템 구축하기
이번 실습의 목표는 단순히 날씨 페이지를 만드는 것을 넘어, "어디서든 쓸 수 있는 날씨 부품(Widget)"을 만드는 것입니다. 우리가 배운 Axios(데이터 통신), Hook(로직 분리), Component(재사용), Router(페이지 이동) 개념을 모두 하나로 합치는 종합 선물 세트 같은 실습입니다.
선수 조건: 팀 소개 페이지 프로젝트
이 실습은 3부 Frontend Chapter 07. React Router 실습에서 만든 '팀 소개 페이지' 프로젝트에서 이어서 진행합니다. 아직 해당 실습을 완료하지 않았다면 먼저 완료하고 돌아와주세요.
🏗️ 아키텍처 설계도
- Logic (두뇌):
useWeather훅 (데이터 가져오기 + 상태 관리) - UI (껍데기):
WeatherWidget컴포넌트 (화면 표시) - Page (배치): 홈, 팀 소개, 날씨 전용 페이지에 위젯 배치
🤖 AI Native Tip
아래 실습에 나온 모든 코드를 복제(Copy-Paste)하지 말고, 여러분이 직접 AI에게 만들어보도록 지시해보세요.
Prompt 예시
서울 기온 데이터를 가져오는 useWeather 훅과 이를 활용해 화면에 보여주는 WeatherWidget 컴포넌트를 만들어줘. axios를 사용하고, 로딩과 에러 처리도 포함해줘.
Step 1. 도구 준비 (Axios 설치)
아직 설치하지 않았다면, 터미널에서 Axios를 설치합니다.
Step 2. 두뇌 만들기: 커스텀 훅 (src/hooks/useWeather.ts)
가장 중요한 로직입니다. '데이터 심부름꾼'과 '화면 관리자'를 분리하여 작성합니다.
// src/hooks/useWeather.ts
import { useState } from 'react';
import axios from 'axios';
export default function useWeather() {
// 1. 상태(State) 바구니들
const [currentTemp, setCurrentTemp] = useState<number | null>(null);
const [hourlyTemps, setHourlyTemps] = useState<number[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// ============================================================
// 함수 A: 데이터 심부름꾼 (getWeatherData)
// 역할: 오직 Axios로 데이터를 가져와서 리턴만 함 (State 모름)
// ============================================================
const getWeatherData = async () => {
const url = "https://api.open-meteo.com/v1/forecast?latitude=37.5&longitude=126.9¤t_weather=true&hourly=temperature_2m";
const response = await axios.get(url);
return response.data; // 데이터를 밖으로 던져줍니다.
};
// ============================================================
// 함수 B: 화면 관리자 (fetchWeather)
// 역할: 로딩 켜고, 심부름꾼(A) 시키고, 받아온 걸 State에 담음
// ============================================================
const fetchWeather = async () => {
try {
setLoading(true);
setError(null);
setCurrentTemp(null);
setHourlyTemps([]);
// 1. 심부름꾼에게 다녀오라고 시킴
const data = await getWeatherData();
// 2. 받아온 데이터를 State에 예쁘게 정리
setCurrentTemp(data.current_weather.temperature);
setHourlyTemps(data.hourly.temperature_2m);
} catch (err) {
setError("날씨 데이터를 가져오는데 실패했습니다.");
} finally {
setLoading(false);
}
};
// 컴포넌트는 심부름꾼(getWeatherData)은 몰라도 되고,
// 관리자(fetchWeather)와 결과값들만 알면 됩니다.
return { currentTemp, hourlyTemps, loading, error, fetchWeather };
}
Step 3. 부품 만들기: 위젯 컴포넌트 (src/components/WeatherWidget.tsx)
이제 위 훅을 사용하는 재사용 가능한 UI 부품을 만듭니다.
// src/components/WeatherWidget.tsx
import useWeather from '../hooks/useWeather';
export default function WeatherWidget() {
// 훅에서 로직을 빌려옵니다.
const { currentTemp, hourlyTemps, loading, error, fetchWeather } = useWeather();
return (
<div className="border border-gray-200 rounded-xl p-6 text-center max-w-[350px] mx-auto bg-white shadow-md">
<h3 className="text-xl font-bold mb-2">🌤️ 서울 날씨</h3>
{/* 로딩 & 에러 처리 */}
{loading && <p className="text-blue-600">데이터 배달 중... 🚚</p>}
{error && <p className="text-red-500">{error}</p>}
{/* 데이터가 있을 때만 화면 표시 */}
{currentTemp !== null && (
<div>
<h2 className="text-4xl font-bold text-blue-600 my-4">{currentTemp}°C</h2>
<div className="bg-gray-100 p-3 rounded-lg text-sm">
<p>🕛 자정: <strong>{hourlyTemps[0]}°C</strong></p>
<p>☀️ 점심: <strong>{hourlyTemps[12]}°C</strong></p>
<p>🌙 저녁: <strong>{hourlyTemps[18]}°C</strong></p>
</div>
</div>
)}
<button
onClick={fetchWeather}
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded cursor-pointer hover:bg-blue-700 transition"
>
{currentTemp ? '새로고침' : '날씨 불러오기'}
</button>
</div>
);
}
Step 4. 여기저기 붙여넣기 (재사용의 마법) 🪄
이제 우리가 만든 WeatherWidget을 필요한 곳마다 붙여넣습니다.
1. 메인 페이지 (src/pages/HomePage.tsx)
import WeatherWidget from '../components/WeatherWidget';
export default function HomePage() {
return (
<div style={{textAlign: 'center'}}>
<h2 className="text-2xl font-bold">🏠 메인 화면</h2>
<p>우리 서비스에 오신 것을 환영합니다.</p>
<hr style={{margin: '20px 0'}} />
{/* 위젯 부착! */}
<WeatherWidget />
</div>
);
}
2. 팀 페이지 (src/pages/TeamPage.tsx)
import WeatherWidget from '../components/WeatherWidget';
export default function TeamPage() {
return (
<div style={{textAlign: 'center'}}>
<h2 className="text-2xl font-bold">😎 팀 소개</h2>
<p>개발자: Bong</p>
{/* 여기에도 부착! */}
<WeatherWidget />
</div>
);
}
3. 날씨 전용 페이지 (src/pages/WeatherPage.tsx)
새로 파일을 만들어 줍니다.
import WeatherWidget from '../components/WeatherWidget';
export default function WeatherPage() {
return (
<div>
<h2 className="text-2xl font-bold text-center">📊 상세 날씨 예보실</h2>
<p className="text-center mb-4">서울 지역의 상세 기상 정보를 확인하는 상황실입니다.</p>
{/* 여기도 부착! */}
<WeatherWidget />
</div>
);
}
Step 5. 라우터 연결하기 (src/App.tsx)
마지막으로 새로 만든 WeatherPage를 라우터에 등록합니다.
// src/App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';
import HomePage from './pages/HomePage';
import TeamPage from './pages/TeamPage';
import WeatherPage from './pages/WeatherPage'; // 임포트 추가
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="team" element={<TeamPage />} />
{/* 날씨 페이지 경로 추가 */}
<Route path="weather" element={<WeatherPage />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
(Layout.tsx의 <Link to="/weather"> 추가는 이전 실습과 동일하게 진행해주세요!)
🧠 마무리: 우리가 무엇을 해냈나요?
- 로직 분리:
getWeatherData(순수 데이터)와fetchWeather(상태 관리)를 나누어 코드를 깔끔하게 정리했습니다. - 캡슐화: 복잡한 Axios 코도는 모두
useWeather훅 안으로 숨겼습니다. - 재사용성:
WeatherWidget하나만 만들어서 홈 화면, 팀 화면, 날씨 화면 세 군데서 동시에 사용했습니다.
이 구조가 바로 실무에서 프론트엔드 개발자가 일하는 방식입니다! 🚀
6. 🚀 심화 실습: "AI 스타일리스트 채용하기"
날씨 위젯에 Gemini를 연동하여, 현재 기온에 맞는 옷차림을 추천해주는 기능을 추가해봅시다. 기존의 '날씨 데이터(Fact)'에 'AI의 판단(Insight)'을 더하는 것은 웹 서비스의 가치를 획기적으로 높이는 방법입니다.
🤖 AI Native Tip
"날씨 데이터와 Gemini를 결합하고 싶어"라는 단순한 말 한마디만으로는 AI가 우리가 원하는 정확한 정답을 내놓기 어렵습니다.
AI에게 제대로 된 코딩을 지시하려면 우리가 먼저 어떤 '재료(API 문서, 라이브러리 설치법, 데이터 구조 등)'가 필요한지 정확히 찾아내어 설명해줘야 합니다. 직접 검색하고 자료를 모은 뒤, AI에게 가장 정교한 주문서를 던져보세요!
- API Key: 앞서 발급받은 Gemini API Key가
.env파일에 잘 저장되어 있는지 확인합니다. (VITE_GEMINI_KEY) - Google Generative AI SDK: Gemini와 쉽게 대화하기 위한 도구를 설치합니다.
Step 1. AI 두뇌 업그레이드 (src/hooks/useWeather.ts)
기존 useWeather 훅에 Gemini를 호출하는 기능을 추가합니다.
// src/hooks/useWeather.ts
import { useState } from 'react';
import axios from 'axios';
// 1. Gemini SDK 불러오기
import { GoogleGenerativeAI } from "@google/generative-ai";
export default function useWeather() {
const [currentTemp, setCurrentTemp] = useState<number | null>(null);
const [hourlyTemps, setHourlyTemps] = useState<number[]>([]);
// 2. 옷차림 추천을 담을 State 추가
const [aiRecommendation, setAiRecommendation] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// ... (getWeatherData 함수는 기존과 동일) ...
// ============================================================
// 함수 C: AI 스타일리스트 (getAiRecommendation) - NEW! ⭐
// 역할: 기온을 입력받아 Gemini에게 옷차림을 물어봄
// ============================================================
const getAiRecommendation = async (temp: number) => {
try {
// 1. API Key로 Gemini 연결 (Vite 방식)
const genAI = new GoogleGenerativeAI(import.meta.env.VITE_GEMINI_KEY);
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
// 2. 프롬프트 작성 (구체적일수록 좋습니다)
const prompt = `현재 서울 기온이 섭씨 ${temp}도야. 이 날씨에 어울리는 한국의 20대 남성 옷차림을 3줄 이내로 간결하게 추천해줘. 말투는 친근한 스타일리스트처럼 해줘.`;
// 3. 질문하고 답변 받기
const result = await model.generateContent(prompt);
const response = await result.response;
const text = response.text();
// 4. 답변을 State에 저장
setAiRecommendation(text);
} catch (error) {
console.error("AI 추천 실패:", error);
setAiRecommendation("AI 스타일리스트가 잠시 자리를 비웠어요. 😅");
}
};
// ============================================================
// 함수 B: 화면 관리자 (fetchWeather) - 수정됨
// ============================================================
const fetchWeather = async () => {
try {
setLoading(true);
setError(null);
setCurrentTemp(null);
setHourlyTemps([]);
// 추천 멘트도 초기화
setAiRecommendation(null);
const data = await getWeatherData();
setCurrentTemp(data.current_weather.temperature);
setHourlyTemps(data.hourly.temperature_2m);
// ★ 중요: 날씨 데이터를 받자마자 AI에게 추천을 의뢰합니다.
// (await를 걸지 않아서, 날씨가 먼저 뜨고 AI 답변은 나중에 뜹니다)
getAiRecommendation(data.current_weather.temperature);
} catch (err) {
setError("날씨 데이터를 가져오는데 실패했습니다.");
} finally {
setLoading(false);
}
};
// 훅에서 aiRecommendation도 리턴해줍니다.
return { currentTemp, hourlyTemps, aiRecommendation, loading, error, fetchWeather };
}
Step 2. 위젯에 AI 말풍선 추가하기 (src/components/WeatherWidget.tsx)
AI의 추천 멘트를 보여줄 공간을 위젯에 추가합니다.
// src/components/WeatherWidget.tsx
import useWeather from '../hooks/useWeather';
export default function WeatherWidget() {
// aiRecommendation도 받아옵니다.
const { currentTemp, hourlyTemps, aiRecommendation, loading, error, fetchWeather } = useWeather();
return (
<div style={{ /* 기존 스타일 유지 */ }}>
<h3 className="text-xl font-bold mb-2">🌤️ 서울 날씨 & AI 코디</h3>
{/* ... (로딩, 에러, 온도 표시 부분 기존과 동일) ... */}
{currentTemp !== null && (
<div>
{/* ... (온도, 시간대별 예보 기존과 동일) ... */}
{/* 👇 AI 추천 영역 추가! ⭐ */}
<div className="mt-4 p-4 bg-blue-50 rounded-lg border-l-4 border-blue-500 text-left">
<p className="font-bold text-blue-600 mb-1">🤖 AI 스타일리스트의 조언:</p>
{aiRecommendation ? (
// AI 답변이 도착했을 때
<p className="text-sm text-gray-700 whitespace-pre-wrap">{aiRecommendation}</p>
) : (
// AI 답변을 기다리는 중일 때
<p className="text-sm text-gray-400">열심히 고민 중이에요... 🤔</p>
)}
</div>
</div>
)}
{/* ... (버튼 기존과 동일) ... */}
</div>
);
}
🎉 결과 확인하기
이제 앱을 실행하고 "날씨 불러오기" 버튼을 눌러보세요.
- 처음엔 날씨 정보(기온, 시간대별 예보)가 먼저 나타납니다.
- AI 말풍선에는 "열심히 고민 중이에요... 🤔"가 뜹니다.
- 잠시 후(약 1~2초 뒤), Gemini가 기온에 맞춰 생성한 옷차림 추천 멘트가 짠! 하고 나타날 것입니다.
💡 핵심 포인트
이 실습을 통해 여러분은 "서로 다른 두 개의 외부 서비스(날씨 API + Gemini API)를 내 서비스 안에서 하나로 융합하는 경험"을 했습니다. 이것이 바로 AI 시대 개발자가 가져야 할 핵심 역량입니다!