api 받아와서 Firestore 데이터베이스에 저장하기

J·2023년 7월 21일
0

todays-recipe

목록 보기
1/9

기존 방식

// api.ts

export interface Recipe {
	// 타입 지정
}

export const getRecipeData = async (): Promise<Recipe[]> => {
  const serviceKey = process.env.REACT_APP_FOODSAFETYKOREA_API_KEY;
  try {
    const responses = await axios.all([
      axios.get(
        `http://openapi.foodsafetykorea.go.kr/api/${serviceKey}/COOKRCP01/json/1/1000`
      ),
      axios.get(
        `http://openapi.foodsafetykorea.go.kr/api/${serviceKey}/COOKRCP01/json/1001/2000`
      ),
    ]);

    const [firstResponse, secondResponse] = responses;
    const allData = firstResponse.data.COOKRCP01.row.concat(
      secondResponse.data.COOKRCP01.row
    );
    console.log('데이터: ', allData);
    return allData;
  } catch (error) {
    console.error('API 호출 실패:', error);
    throw error;
  }
};

기존 방식은 이렇게 api를 받아와 export해서,

// Recipe.tsx

import { useState, useEffect } from 'react';
import { getRecipeData, Recipe } from '../apis/api';
import RecipeBox from '../components/recipe/RecipeBox';

const RecipePage = () => {
  const [recipeData, setRecipeData] = useState<Recipe[]>([]);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await getRecipeData();
        setRecipeData(data);
      } catch (error) {
        console.error('데이터 불러오기 실패:', error);
      }
    };
    fetchData();
  }, []);

  return ( ~ );
};

export default RecipePage;

필요한 페이지에서 import해서 사용했음.

받아오는 데이터가 많아 렌더링에 오랜 시간이 걸려 점점 개발 속도가 지체되어 일단 데이터 캐싱을해서 보완을 했다. 그리고 다음 단계인 무한 스크롤 코드를 짜고 있는데 이것 저것 수정하면서 지속적으로 데이터를 요청하다보니 이번엔 CORS 정책에 막혔음. 지난번과 같이 프록시 서버를 설정해 우회해야하는 문제는 아니고 지속적인 GET 요청으로 일일 할당량을 초과해 api 호출에 실패한 것.

그래서 api를 한 번만 호출해 Firestore db에 저장을 해서 데이터를 사용해야겠다고 생각함. 마침 실시간 데이터도 아니어서 필요할 때마다 업데이트를 해주면 되겠다.

Firestore db에 저장하기

// Admin.tsx

import { useState } from 'react';
import axios from 'axios';
import { addDoc, collection } from 'firebase/firestore';
import { dbService } from '../apis/firebase';

interface Recipe {
	// 타입 지정
}

const Admin = () => {
  const [recipeList, setRecipeList] = useState<Recipe[]>([]);
  const getRecipeListHandler = async () => {
    try {
      const serviceKey = process.env.REACT_APP_FOODSAFETYKOREA_API_KEY;
      const responses = await axios.all([
        axios.get(
          `http://openapi.foodsafetykorea.go.kr/api/${serviceKey}/COOKRCP01/json/1/1000`
        ),
        axios.get(
          `http://openapi.foodsafetykorea.go.kr/api/${serviceKey}/COOKRCP01/json/1001/2000`
        ),
      ]);
      const [firstResponse, secondResponse] = responses;
      const allData = firstResponse.data.COOKRCP01.row.concat(
        secondResponse.data.COOKRCP01.row
      );
      
      console.log('데이터: ', allData);
      
      setRecipeList(allData);
      
    } catch (error) {
      console.error('레시피 리스트를 가져오지 못했어요. :', error);
    }
    {
      recipeList.map((recipe) => {
        addDoc(collection(dbService, 'recipe-list'), {
          ATT_FILE_NO_MAIN: recipe?.ATT_FILE_NO_MAIN,
   		  	// ... 내가 원하는 데이터를 넣어준다.
        });
      });
    }
  };
  return (
    <>
      <p onClick={getRecipeListHandler}>파이어스토어에 데이터 넣어주기</p>
    </>
  );
};

이렇게 기존 방법과 같이 api를 받아온 다음, state를 만들어 받아온 데이터를 map으로 뿌려 collection에 addDoc 해주면 된다.
나는 버튼을 눌렀을 때 'recipe-list'라는 collection에 데이터를 저장하고 싶어서 이렇게 코드를 만들었다.

이렇게 클릭 한 번으로 내가 원하는 api 정보들이 하나의 컬렉션에 저장되었다. 이제 데이터가 필요할 때마다 GET 요청 대신 저 녀석들을 가져와 뿌려주면 되겠다.

컬렉션에서 데이터 가져오기

Recipe.tsx 코드를 다음과 같이 변경했다.

import { useState, useEffect } from 'react';
import { Recipe } from '../pages/Admin';
import RecipeBox from '../components/recipe/RecipeBox';
import { collection, getDocs } from 'firebase/firestore';
import { dbService } from '../apis/firebase';

const RecipePage = () => {
  const [recipeData, setRecipeData] = useState<Recipe[]>([]);
  
  const getRecipeData = async () => {
    const querySnapshot = await getDocs(collection(dbService, 'recipe-list'));
    const recipeDataBase: Recipe[] = [];

    querySnapshot.forEach((doc) => {
      // 일단 any 처리
      const newRecipe: any = {
        id: doc.id,
        ...doc.data(),
      };
      recipeDataBase.push(newRecipe);
    });
    setRecipeData(recipeDataBase);
  };

  useEffect(() => {
    getRecipeData();
  }, []);

  return ( ~ );
};

export default RecipePage;

이렇게 getDocs로 지정한 컬렉션의 데이터를 가져오면 된다.

profile
벨로그로 이사 중

0개의 댓글