Frontend ๐Ÿ“š/React

[React] TMDB API๋ฅผ ํ™œ์šฉํ•œ ๋„ทํ”Œ๋ฆญ์Šค ํด๋ก  ์ฝ”๋”ฉ - 3. API ํ˜ธ์ถœ๊ณผ Local Storage๋ฅผ ํ™œ์šฉํ•œ ์˜ํ™” ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

leejaejae 2024. 12. 6. 14:22

API ํ˜ธ์ถœ๊ณผ Local Storage๋ฅผ ํ™œ์šฉํ•œ ์˜ํ™” ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

์ด๋ฒˆ ๋‹จ๊ณ„์—์„œ๋Š” TMDB API๋ฅผ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ํ˜ธ์ถœ๊ณผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํ™œ์šฉํ•œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” API ํ˜ธ์ถœ๊ณผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ๊ด€๋ จ ์ฝ”๋“œ์˜ ์ฃผ์š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.


1. TMDB API ์„ค์ •

  • TMDB(The Movie Database)๋Š” ์˜ํ™” ๋ฐ์ดํ„ฐ API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” TMDB API๋ฅผ ์‚ฌ์šฉํ•ด ์ธ๊ธฐ ์˜ํ™”, ํŠน์ • ์˜ํ™” ์ •๋ณด, ์˜ํ™” ๊ฒ€์ƒ‰ ๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

API ์„ค์ • ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

import axios from "axios";

// TMDB API ๊ธฐ๋ณธ ์„ค์ •
const BASE_URL = "<https://api.themoviedb.org/3>";
const API_KEY = process.env.REACT_APP_TMDB_API_KEY; // ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ API ํ‚ค ์ฝ๊ธฐ
const BEARER_TOKEN = process.env.REACT_APP_TMDB_BEARER_TOKEN;

// Axios ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
const api = axios.create({
  baseURL: BASE_URL,
  params: {
    api_key: API_KEY,
    language: "en-US", // ๊ธฐ๋ณธ ์–ธ์–ด ์„ค์ •
  },
  headers: {
    accept: "application/json",
    Authorization: `Bearer ${BEARER_TOKEN}`, // Authorization ํ—ค๋” ์ถ”๊ฐ€
  },
});
  • BASE_URL: TMDB API์˜ ๊ธฐ๋ณธ URL.
  • API_KEY์™€ BEARER_TOKEN: ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ ๋ณด์•ˆ ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • Axios ์ธ์Šคํ„ด์Šค: ๋งค๋ฒˆ API ํ˜ธ์ถœ ์‹œ ๊ธฐ๋ณธ URL๊ณผ ๊ณตํ†ต ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์„ค์ •ํ•˜์ง€ ์•Š๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

2. TMDB API ํ™œ์šฉ

TMDB API๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ด ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•œ ์ฃผ์š” ๊ธฐ๋Šฅ๋“ค์ž…๋‹ˆ๋‹ค:

  • ์ธ๊ธฐ ์˜ํ™” ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
// ์ธ๊ธฐ ์˜ํ™” ๊ฐ€์ ธ์˜ค๊ธฐ
export const getPopularMovies = async (page = 1) => {
  try {
    const response = await api.get("/movie/popular", {
      params: { page },
    });
    return response.data;
  } catch (error) {
    console.error("Error fetching popular movies:", error);
    throw error;
  }
};
  • ์˜ํ™” ๊ฒ€์ƒ‰
// ์˜ํ™” ๊ฒ€์ƒ‰
export const searchMovies = async (query, page = 1) => {
  try {
    const response = await api.get("/search/movie", {
      params: { query, page },
    });
    return response.data;
  } catch (error) {
    console.error("Error searching movies:", error);
    throw error;
  }
};
  • ํŠน์ • ์˜ํ™” ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
// ํŠน์ • ์˜ํ™” ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
export const getMovieDetails = async (movieId) => {
  try {
    const response = await api.get(`/movie/${movieId}`);
    return response.data;
  } catch (error) {
    console.error("Error fetching movie details:", error);
    throw error;
  }
};

3. ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€(Local Storage) ํ™œ์šฉ

์‚ฌ์šฉ์ž์˜ ์„ ํ˜ธ ์˜ํ™” ๋ชฉ๋ก, ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ๋“ฑ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋˜๋ฉฐ, ์ง€์†์ ์ธ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ๋ฐ์ดํ„ฐ ์ €์žฅ
// Local Storage ์ €์žฅ
export const saveToLocalStorage = (key, value) => {
  localStorage.setItem(key, JSON.stringify(value));
};
  • ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
// Local Storage์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
export const getFromLocalStorage = (key) => {
  const value = localStorage.getItem(key);
  return value ? JSON.parse(value) : null;
};
  • ๋ฐ์ดํ„ฐ ์‚ญ์ œ
// Local Storage์—์„œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
export const removeFromLocalStorage = (key) => {
  localStorage.removeItem(key);
};

4. ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

  • ์ฆ๊ฒจ์ฐพ๊ธฐ ์˜ํ™” ๋ชฉ๋ก ์ €์žฅ์ด ํ•จ์ˆ˜๋Š” ์˜ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ์ค‘๋ณต ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
// ์ฆ๊ฒจ์ฐพ๊ธฐํ•œ ์˜ํ™” ๋ชฉ๋ก ์ €์žฅ
export const saveFavoriteMovies = (movie) => {
  let favoriteMovies = getFromLocalStorage("favoriteMovies") || [];
  // ์ค‘๋ณต ๋ฐฉ์ง€
  if (!favoriteMovies.some((fav) => fav.id === movie.id)) {
    favoriteMovies.push(movie);
    saveToLocalStorage("favoriteMovies", favoriteMovies);
  }
};
  • ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ์ €์žฅ์ตœ๋Œ€ 5๊ฐœ์˜ ๊ฒ€์ƒ‰์–ด๋งŒ ์œ ์ง€ํ•˜๋ฉฐ, ์ค‘๋ณต ๊ฒ€์ƒ‰์–ด๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
// ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ์ €์žฅ
export const saveRecentSearch = (searchTerm) => {
  let recentSearches = getFromLocalStorage("recentSearches") || [];
  // ๊ฒ€์ƒ‰์–ด ์ค‘๋ณต ๋ฐฉ์ง€
  if (!recentSearches.includes(searchTerm)) {
    recentSearches.push(searchTerm);
    // ์ตœ๋Œ€ 5๊ฐœ์˜ ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด๋งŒ ์ €์žฅ
    if (recentSearches.length > 5) {
      recentSearches.shift(); // ์ฒซ ๋ฒˆ์งธ ๊ฒ€์ƒ‰์–ด ์ œ๊ฑฐ
    }
    saveToLocalStorage("recentSearches", recentSearches);
  }
};

๐Ÿ› ๏ธ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์™€ API ํ™œ์šฉ์˜ ๊ฒฐํ•ฉ

์œ„์—์„œ ๊ตฌํ˜„ํ•œ TMDB API ํ˜ธ์ถœ๊ณผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํ™œ์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  1. ์ธ๊ธฐ ์˜ํ™” ๋ชฉ๋ก ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  2. API๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ตœ์‹  ์ธ๊ธฐ ์˜ํ™”๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ฆ๊ฒจ์ฐพ๊ธฐ ์˜ํ™” ์ €์žฅ
  4. ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์˜ํ™”๋ฅผ ํด๋ฆญํ•ด ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ๋Š” ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋˜๋ฉฐ, ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
  5. ๊ฒ€์ƒ‰์–ด ์ €์žฅ
  6. ์‚ฌ์šฉ์ž์˜ ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด๋ฅผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜์—ฌ, ๋น ๋ฅธ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”— ๋ธ”๋กœ๊ทธ์—์„œ ๋‹ค๋ฃฐ ๋‚ด์šฉ ์š”์•ฝ

์ด ํฌ์ŠคํŒ…์—์„œ๋Š” ๋‹ค์Œ ๋‚ด์šฉ์„ ์ž์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค:

  • TMDB API ์„ค์ • ๋ฐ ํ™œ์šฉ ๋ฐฉ๋ฒ•
  • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ ์ €์žฅ๊ณผ ๊ด€๋ฆฌ
  • ์ธ๊ธฐ ์˜ํ™”, ๊ฒ€์ƒ‰์–ด, ์ฆ๊ฒจ์ฐพ๊ธฐ ์˜ํ™” ๋ชฉ๋ก ์ €์žฅ ๊ตฌํ˜„

๋‹ค์Œ ๋‹จ๊ณ„์—์„œ๋Š” UI ์ปดํฌ๋„ŒํŠธ์™€ ๋กœ์ง ๊ฒฐํ•ฉ์— ๋Œ€ํ•ด ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜Š