03. Axios로 TMDB API 연결하기
요약
Gemini CLI로 구현하기 — Axios 인스턴스 & API 연결
npx gemini-
1src/api/axios.js 파일을 작성해줘. axios.create()로 TMDB API 전용 인스턴스를 만들어야 해. baseURL은 https://api.themoviedb.org/3/, api_key는 import.meta.env.[API 키 환경변수명], language는 ko-KR, region은 KR로 설정해줘.
- 사용 가이드:
.env파일에VITE_TMDB_API_KEY=본인의키를 저장한다.[API 키 환경변수명]을VITE_TMDB_API_KEY로 바꾼다.
1. API란 무엇인가?
API(Application Programming Interface, 에이피아이)는 프로그램끼리 데이터를 주고받는 약속된 통로이다.
레스토랑에 비유하면 이렇다. 손님(우리 앱)이 웨이터(API)에게 주문서(요청)를 전달하면, 주방(서버)이 음식(데이터)을 만들어서 웨이터가 다시 가져다준다.
TMDB API도 마찬가지이다. 우리가 “인기 영화 목록 줘”라고 요청하면, TMDB 서버가 JSON(제이슨) 형태의 영화 데이터를 돌려준다.
2. Axios는 왜 쓸까?
| 기능 | fetch | Axios |
|---|---|---|
| JSON 자동 변환 | ❌ .json() 호출 필요 | ✅ 자동 변환 |
| 기본 URL 설정 | ❌ 매번 전체 URL 작성 | ✅ baseURL 한 번 설정 |
| 요청 가로채기(인터셉터) | ❌ 없음 | ✅ 지원 |
| 에러 처리 | 404도 성공으로 처리 | 자동으로 에러 발생 |
3. api/axios.js 작성
src/api/ 폴더 안에 axios.js 파일을 새로 만들고, 아래 코드를 입력한다. 이 파일은 TMDB에 데이터를 요청할 때 사용하는 주문서 양식이다. 매번 주소와 설정을 반복하지 않고, 여기서 한 번만 정해두면 된다.
1import axios from "axios";2
3// TMDB API 설정4const api = axios.create({5 baseURL: "https://api.themoviedb.org/3/",6 params: {7 api_key: import.meta.env.VITE_TMDB_API_KEY,8 language: "ko-KR",9 region: "KR",10 },11});12
13export default api;| 줄 | 설명 |
|---|---|
| 1 | axios 라이브러리를 가져온다. |
| 4 | axios.create()로 TMDB 전용 인스턴스(인스턴스, 설정이 적용된 복사본)를 만든다. |
| 5 | baseURL에 TMDB API의 기본 주소를 넣는다. 이후 api.get('movie/popular')만 쓰면 자동으로 https://api.themoviedb.org/3/movie/popular로 요청이 간다. |
| 7 | import.meta.env.VITE_TMDB_API_KEY는 .env 파일에 저장한 API 키를 읽어오는 Vite 문법이다. |
| 8 | language: "ko-KR" — 모든 요청에 한국어 응답을 자동으로 요청한다. 매번 ?language=ko-KR을 붙일 필요가 없다. |
| 9 | region: "KR" — 한국 지역 기준 데이터(개봉일 등)를 반환한다. |
| 13 | api를 기본값으로 내보낸다. 다른 파일에서 import api로 사용한다. |
이전 교안에서는 baseURL이 https://api.themoviedb.org/3/movie/였다. 이번에는 https://api.themoviedb.org/3/로 변경했다.
| baseURL | 사용할 수 있는 API |
|---|---|
.../3/movie/ | 영화 관련만 (popular, now_playing 등) |
.../3/ | 영화 + 검색 + TV 등 모든 API |
검색 기능(search/movie)과 카테고리 기능(movie/popular)을 모두 사용하려면 /3/까지만 설정해야 한다.
1params: {2 api_key: import.meta.env.VITE_TMDB_API_KEY,3 language: "ko-KR",4 region: "KR",5},이렇게 params에 공통 파라미터를 넣으면, 모든 API 요청에 자동으로 ?api_key=...&language=ko-KR®ion=KR이 붙는다. 각 컴포넌트에서 매번 반복할 필요가 없어진다.
4. axios.create()의 동작 원리
axios.create() 없이:
1const res1 = await axios.get('https://api.themoviedb.org/3/movie/popular?api_key=abc123&language=ko-KR®ion=KR');2const res2 = await axios.get('https://api.themoviedb.org/3/search/movie?api_key=abc123&language=ko-KR®ion=KR&query=어벤져스');axios.create() 사용:
1const res1 = await api.get('movie/popular');2const res2 = await api.get('search/movie', { params: { query: '어벤져스' } });코드가 훨씬 짧고 읽기 쉬워진다.
5. 환경 변수(.env) 작동 원리
| 단계 | 설명 |
|---|---|
| 1 | .env 파일에 VITE_로 시작하는 변수를 작성한다. |
| 2 | Vite 개발 서버가 시작될 때 이 값을 읽어들인다. |
| 3 | 코드에서 import.meta.env.VITE_TMDB_API_KEY로 접근하면 문자열이 반환된다. |
주의
VITE_ 접두사가 없는 변수는 브라우저 코드에서 접근할 수 없다. 반드시 VITE_를 붙여야 한다.
6. App.jsx
App.jsx는 앱 전체를 감싸는 **루트 컴포넌트(컴포넌트, 화면 조각)**이다. 여기서 영화 데이터를 한 번 불러온 뒤, 자식 페이지에 전달한다.
6-1. import 추가
파일 맨 위에 아래 세 줄을 추가한다.
1import { useState, useEffect } from "react";2import { Outlet } from "react-router-dom";3import api from "./api/axios";| 줄 | 설명 |
|---|---|
| 1 | useState — 데이터를 저장하는 상자. useEffect — 컴포넌트가 화면에 나타날 때 실행할 코드를 등록한다. |
| 2 | Outlet — 현재 URL에 맞는 페이지를 이 자리에 끼워 넣는다. |
| 3 | 앞서 만든 TMDB 전용 axios 인스턴스(인스턴스, 설정이 담긴 복사본)를 가져온다. |
6-2. 상태(state)와 데이터 요청 함수 추가
App 함수 안에 아래 코드를 추가한다.
1export default function App() {2 const [now, setNow] = useState([]); // 13
4 async function loadMovie() { // 25 const res1 = await api.get(`movie/now_playing`); // 36 const data = res1.data.results; // 47 setNow(data); // 58 }9
10 useEffect(() => { // 611 loadMovie(); // 712 }, []); // 813
14 return (15 <>16 <Header />17 <Outlet context=\{\{ now \}\} /> // 918 </>19 );20}| 줄 | 설명 |
|---|---|
| 1 | now — 현재 상영 중인 영화 목록을 담는 상자. 처음에는 빈 배열([])이다. |
| 2 | loadMovie — 영화 데이터를 불러오는 함수. async(어싱크)를 붙이면 내부에서 await(어웨이트)를 쓸 수 있다. |
| 3 | api.get('movie/now_playing') — TMDB에 “현재 상영 중인 영화 목록”을 요청한다. 응답이 올 때까지 기다린다(await). |
| 4 | 응답 데이터에서 영화 배열만 꺼낸다. TMDB는 항상 results 안에 목록을 넣어 준다. |
| 5 | 꺼낸 배열을 now 상자에 저장한다. 저장되면 화면이 자동으로 업데이트된다. |
| 6 | useEffect — 컴포넌트가 처음 화면에 나타날 때 딱 한 번 실행된다. |
| 7 | loadMovie()를 호출해 영화 데이터를 불러온다. |
| 8 | [] — 빈 배열을 넣으면 “처음 한 번만 실행”이라는 뜻이다. |
| 9 | Outlet에 context(컨텍스트)로 now를 전달한다. 자식 페이지에서 이 데이터를 꺼내 쓴다. \{\{ \}\}는 JSX에서 객체를 전달하는 문법이다. |
요약
Outlet context로 데이터를 전달하면, 자식 페이지에서 useOutletContext() 훅으로 꺼내 쓸 수 있다. 다음 단계에서 배운다.
7. TMDB API 응답 구조
api.get('movie/popular')을 호출하면 아래와 같은 구조의 데이터가 돌아온다.
1{2 "page": 1,3 "results": [4 {5 "id": 550,6 "title": "파이트 클럽",7 "poster_path": "/pB8BM7pdSp6B6Ih7QZ4DrQ3PmJK.jpg",8 "vote_average": 8.4,9 "release_date": "1999-10-15",10 "overview": "줄거리..."11 }12 ],13 "total_pages": 50014}| 필드 | 의미 |
|---|---|
results | 영화 목록 배열. 여기서 각 영화 객체를 꺼내 화면에 표시한다. |
poster_path | 포스터 이미지 경로. 앞에 https://image.tmdb.org/t/p/w500을 붙여야 완전한 URL이 된다. |
vote_average | 평점 (0~10점). |
8. 전체 코드
1import axios from "axios";2
3// TMDB API 설정4const api = axios.create({5 baseURL: "https://api.themoviedb.org/3/",6 params: {7 api_key: import.meta.env.VITE_TMDB_API_KEY,8 language: "ko-KR",9 region: "KR",10 },11});12
13export default api;