현재 프로젝트에서 영상으로 이루어진 플레이리스트를 공유하고 업로드 할 수 있는 플랫폼을 개발하고 있다.

우리 팀은 사용자가 원하는 주제의 영상을 가져와서 플레이리스트를 구성하고 업로드 하는 방식으로 가고있기 때문에,
사용자가 유튜브 링크를 입력하면 해당 영상의 썸네일, 제목, 채널 이름 등 영상 정보를 불러와 보여주는 기능이 필요하다!

또한, 영상 재생도 가능해야 하기 때문에, 단순히 링크를 저장하는 것이 아니라 해당 링크로부터 유튜브 영상 ID를 추출하고, 유튜브 API를 통해 영상 정보를 가져오는 로직을 구현해야 한다.


🤔 왜 YouTube Data API를 사용했을까?

유튜브 링크에서 정보를 가져오는 방법에는 단순하게 HTML 메타 태그를 파싱하는 방법도 있지만,
가장 정확하고 안정적인 방법은 YouTube에서 공식으로 제공하는 Data API v3를 활용하는 것이다.

이 API를 통해, 특정 영상 ID에 대한 정보를 요청할 수 있고,
썸네일 URL, 제목, 채널명, 업로드 시간, 조회수 등의 정보까지 모두 받을 수 있다.


API 키 발급 및 설정

API 키 발급 과정은 무척 간단하다.
아래에 정리해둔 일련의 과정들을 따라하면 API를 통해 유튜브 영상들을 프로젝트에서 불러올 준비를 마친 것이다.

  1. Google Cloud Console에 접속
  2. 새 프로젝트 생성
  3. "YouTube Data API v3" 검색 후 API 사용 설정
  4. "사용자 인증 정보" > API 키 생성
  5. 프로젝트 루트에 .env 파일을 만들고 아래처럼 설정
    (Vite 환경이기 때문에 반드시 VITE_ prefix 사용)
VITE_YOUTUBE_API_KEY=발급받은_유튜브_API_키
  1. .gitignore.env 추가하여 깃에 올라가지 않도록 처리

유튜브 영상 ID 추출 함수

유튜브 링크는 다양한 형태로 들어올 수 있다.

예시:

이러한 링크에서 영상 ID만 정확히 추출하기 위한 함수를 작성하였다.

export function extractVideoId(url: string): string | null {
  try {
    const parsedUrl = new URL(url);
    if (parsedUrl.hostname.includes("youtube.com")) {
      return parsedUrl.searchParams.get("v");
    }
    if (parsedUrl.hostname === "youtu.be") {
      return parsedUrl.pathname.slice(1);
    }
    return null;
  } catch {
    return null;
  }
}
  • new URL(url)을 통해 문자열 링크를 URL 객체로 파싱한다.
  • youtube.com 형식은 ?v= 쿼리에서 ID를 추출하고,
  • youtu.be 형식은 pathname에서 슬래시를 제외하고 추출한다.
  • 잘못된 URL이 들어올 경우 null을 반환해 안전하게 처리한다.

영상 정보 요청 함수

영상 ID가 준비되었으면, 이제 이를 유튜브 API에 전달하여 영상 정보를 받아올 수 있다.

import axios from "axios";

const API_KEY = import.meta.env.VITE_YOUTUBE_API_KEY;

export async function fetchYoutubeVideoData(videoId: string) {
  const url = "https://www.googleapis.com/youtube/v3/videos";

  try {
    const response = await axios.get(url, {
      params: {
        part: "snippet",
        id: videoId,
        key: API_KEY,
      },
    });

    const items = response.data.items;
    if (items && items.length > 0) {
      const snippet = items[0].snippet;
      return {
        videoId,
        title: snippet.title,
        thumbnail: snippet.thumbnails.medium.url,
        channelTitle: snippet.channelTitle,
      };
    } else {
      throw new Error("영상 정보를 찾을 수 없습니다.");
    }
  } catch (error) {
    console.error("유튜브 API 요청 실패:", error);
    throw error;
  }
}

각 파라미터 설명

  • part: "snippet": 썸네일, 제목, 채널명 등 기본 정보 요청
  • id: 영상 ID
  • key: 발급받은 API 키

응답은 items[0].snippet에 영상 정보가 담겨 있고, 그 안에서 필요한 값만 골라서 반환했다.


테스트용 컴포넌트 (YoutubeFetcher)

해당 기능이 실제로 잘 작동하는지 테스트하기 위해 간단한 테스트 컴포넌트를 만들었다.

// src/shared/component/YoutubeFetcher.tsx

import { useState } from "react";
import { extractVideoId } from "@/shared/utils/youtubeUtils";
import { fetchYoutubeVideoData } from "@/api/youtubeApi";

const YoutubeFetcher = () => {
  const [url, setUrl] = useState("");
  const [videoData, setVideoData] = useState<any>(null);
  const [error, setError] = useState<string | null>(null);

  const handleFetch = async () => {
    const videoId = extractVideoId(url);
    if (!videoId) {
      setError("유효한 유튜브 링크가 아닙니다.");
      return;
    }

    try {
      const data = await fetchYoutubeVideoData(videoId);
      setVideoData(data);
    } catch {
      setError("영상 정보를 불러오지 못했습니다.");
    }
  };

  return (
    <div>
      <input
        value={url}
        onChange={(e) => setUrl(e.target.value)}
        placeholder="유튜브 링크를 입력하세요"
      />
      <button onClick={handleFetch}>영상 정보 가져오기</button>

      {error && <p style={{ color: "red" }}>{error}</p>}

      {videoData && (
        <div>
          <img src={videoData.thumbnail} alt="썸네일" />
          <p>제목: {videoData.title}</p>
          <p>채널: {videoData.channelTitle}</p>
        </div>
      )}
    </div>
  );
};

export default YoutubeFetcher;
  • 유튜브 링크를 입력하고 버튼을 누르면
  • 영상 ID를 추출하고
  • API로 정보를 요청하여 화면에 렌더링한다

직접 테스트해본 결과

공유 링크 형식도 잘 작동하고, 정상적으로 영상 정보가 출력되는 것을 확인할 수 있었다!


🤓 새롭게 배운점!

  • 유튜브 API는 구조만 이해하면 굉장히 간단하고 안정적으로 사용할 수 있었다.

  • 링크에서 ID를 추출하는 부분은 처음엔 사소해 보였지만, 실제로는 가장 까다롭고 중요한 부분이었다.

  • URL 객체를 사용하여 링크를 파싱하는 방식이 훨씬 안전하고 실용적이라는 것을 배웠다.


😶‍🌫️마치며...

이번 과정을 통해 하나의 기능을 만들기 위해 어떤 흐름으로 개발을 진행해야 하는지 몸소 경험할 수 있었다.
또한 단순히 API를 호출하는 것 이상의 경험, 예를 들어 링크 파싱, 에러 핸들링, 환경변수 관리 같은 현실적인 프론트엔드 개발 감각도 함께 키울 수 있었다.

이 기능은 앞으로 실제 플랫폼의 영상 등록 기능이나 플레이어 컴포넌트와도 연결될 수 있다.

profile
아는만큼 보이는🌱👀

0개의 댓글