본문 바로가기
사이드프로젝트

사이드 프로젝트 도전기 (Day 3) – 프론트와 백엔드 첫 연결

by Jaejin Sim 2025. 9. 4.
반응형

사이드 프로젝트 도전기 (Day 3) – 프론트와 백엔드 첫 연결

바이브코딩으로 만들어진 프론트엔드와 백엔드 코드를 실제로 연동하는 작업에 들어갔습니다.
처음엔 막막했지만, 하루 종일 부딪혀 본 끝에 데이터 통신의 첫 단계를 마무리할 수 있었습니다.


1. 프론트엔드에서의 막막함

연동을 시도하면서 가장 크게 느낀 건,
AI가 짜준 코드를 그대로 쓰면 내 것이 되지 않는다”는 점이었습니다.

API 연동 방법을 AI에게 물어보면 답은 주지만,
저는 API Key를 헤더에 넣어야 하는 구조였기 때문에 단순히 클라이언트 컴포넌트에서 사용할 수 없었습니다.

이 과정에서 Next.js의 api 디렉토리와 route.ts 개념을 새롭게 알게 되었습니다.

 
(백엔드 API를 프론트에서 바로 호출하지 않고, Next.js 서버 라우트를 거쳐 처리)
// src/app/api/portfolios/route.ts 

import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url);
  const page = searchParams.get("page") || "1";
  const limit = searchParams.get("limit") || "10";

  const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/api/portfolios?page=${page}&limit=${limit}`;
  const response = await fetch(apiUrl, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": `${process.env.API_KEY}`,
    },
  });

  const data = await response.json();
  return NextResponse.json(data);
}

그리고 프론트 페이지(feed/page.tsx)에서는 이 라우트를 호출하여 실제 데이터를 불러오는 로직을 구성했습니다.

// src/app/feed/page.tsx 

export default function FeedPage() {
  const [selectedFilter, setSelectedFilter] = useState('전체');
  const [searchQuery, setSearchQuery] = useState('');
  const [portfolios, setPortfolios] = useState<PortfolioSummary[]>([]);

useEffect(() => {
    const fetchPortfolios = async () => {
      try {
        const response = await fetch('/api/portfolios');
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        console.log('🔍 Full API Response:', data);
        console.log('📊 Portfolio Data:', data.data);
        console.log('📈 Total Count:', data.total);
        
        // ✅ 실제 포트폴리오 배열만 설정
        if (data.data && data.data.length > 0) {
          setPortfolios(data.data);
        } else {
          // API 데이터가 없으면 샘플 데이터 사용
          console.log('📝 Using sample data as fallback');
          setPortfolios(SAMPLE_PORTFOLIOS);
        }
      } catch (error) {
        console.error('❌ Error fetching portfolios:', error);
        console.log('📝 Using sample data as fallback');
        // 오류 발생 시 샘플 데이터 사용
        setPortfolios(SAMPLE_PORTFOLIOS);
      }
    };
    
    fetchPortfolios();
  }, []);

2. FastAPI 모델 스키마 수정

백엔드에서는 AI가 만들어 준 FastAPI 모델이 마음에 들지 않아 직접 손을 봤습니다.

  1. UUID → 문자열 변환
    • 기본 id 타입이 UUID였는데, str 변환이 필요해서 DB 컬럼을 character varying(36)으로 변경.
  2. FK 제거
    • 테이블 간 FK 설정을 모두 없애고, 단순히 인덱스만 두어 DB 의존성을 줄임.
  3. 컬럼 코멘트 추가
    • 각 컬럼에 설명이 없어 주석을 달아 가독성을 높임.
  4. 누락된 컬럼 등록
    • 프론트엔드에서 필요한 컬럼들이 빠져 있어 새로 추가.

사실 몇 개 파일만 수정했을 뿐인데, 이 작업에 하루를 다 썼습니다.


3. 오늘의 깨달음

프론트엔드 코드도, 백엔드 코드도 결국엔 단순한 몇 줄의 코드를 얻기 위해 수많은 시행착오가 필요했습니다.
그리고 오늘 느낀 점은 분명합니다.

👉 “이해 없이 완성된 코드를 수정·개선하려면 오히려 더 많은 시간이 든다.”


4. 마무리

비록 하루 종일 삽질을 했지만, 그래도 프론트와 백엔드 간 데이터 통신의 첫 단계를 완성한 건 큰 성과였습니다.

내일은 또 어떤 삽질(?)이 기다릴지 모르지만, 그래도 한 걸음씩 나아가야겠죠.
내일도 화이팅! 💪

반응형