프로젝트/Resthub

[Resthub#개발일지6] React에서 공공데이터 API 가져오기 (+전처리까지)

hodo- 2024. 1. 21. 03:56

토이 프로젝트를 만들면서 레시피에 대한 공공데이터 API가 필요하여
공공데이터활용에서 제공하는 Open API를 가져오려고 한다.

1. Open API 신청하기

https://www.foodsafetykorea.go.kr/apiMain.do

 

식품안전나라

공공데이터 검색 식품의약품안전처 및 연계기관에서 개방하는 데이터를 검색할 수 있습니다. 검색어를 입력하세요. --> 검색

www.foodsafetykorea.go.kr

여기서 원하는 데이터를 검색하고 해당 데이터에 Open API 이용 신청을 하면 된다.

요청주소, 요청인자, 출력항목이 나와있어서 처음 Open API를 사용해보는 나도 쉽게 이용할 수 있었다.

제공해주는 데이터가 많기 때문에 그 중 내가 필요한 데이터만 가져오기 위해 JSON형식으로  가져왔다.
샘플 데이터로 미리 어떻게 생겼는지 확인을 해보면 아래와 같다.

2. 발급받은 API KEY 숨기기

우선 발급받은 API KEY는 민감한 정보기 때문에 외부에 노출되지 않도록 따로 숨겨야 한다.
소스 코드에 직접 포함하지 않고 환경 변수로 사용하도록 한다.

  1. .env 파일에 환경변수로 만든다.
  2. 터미널에 npm install dotenv 라이브러리 설치 (환경 변수를 로드하는데 도움을 주는 라이브러리)
  3. .gitignore파일에 .env 내용 작성하여 .env 파일 숨기기
  4. .env파일에 REACT_APP으로 시작하는 변수명으로 해서 REACT_APP_APIKEY = 자신의 API 로 작성한다
  5. API KEY를 작성하는 부분에 process.env.환경 변수명 으로 작성하면 된다.

    Vite환경에서는 VITE_API_RECIPE_KEY로 API 저장하고import.meta.env.VITE_API_RECIPE_KEY로 환경 변수명 작성함

3. API 가져오기

recipe.ts
API에서 원하는 데이터를 가져온다

const response = await axios.get(
    `https://openapi.foodsafetykorea.go.kr/api/${KEY}/COOKRCP01/json/1/30/${ACTION}${food}`,
);

KEY에는 발급받은 KEY값 가져오고 food는 식재료를 의미한다

if (response.data.COOKRCP01.total_count === "0") {
    return false;
}

해당하는 레시피가 없는 경우가 있어서 total_count가 0이라면 false를 반환하도록 했다.

레시피를 불러오면

레시피의 정보들이 담겨서 온다.

여기서 필요한 정보만 빼내서 사용하고, 또 내가 원하는 데이터 형식으로 받기 위해 필터링 과정이 필요하다.

필터링이 필요한 것은 아래와 같다.

1. 식재료 (전처리 필요)
2. 메뉴얼 (각 메뉴마다 매뉴얼이 최소 1개에서 최대 20개까지 랜덤으로 있으니 있는 메뉴얼만 저장)

우선 식재료 정보가

이런 식으로 정형화되지 않은 상태로 온다.... 매우 절망적이다....
결국 데이터를 하나하나 보면서 전처리 과정을 거칠 수밖에 없었다..

데이터가 한두개의 형식이 아닌 여러 형식으로 이루어져있어서 내가 원하는 형식으로 가져오기 위해 데이터전처리하는 과정이 쉽지 않았다..
이렇게 전처리 과정을 거쳤더라도 제대로 필터링이 되지 않은 데이터가 있을 것이고 그러한 데이터를 발견하게 되면 그때 또 데이터 전처리를 해줘야 했다.

테스트 코드가 있으면 좋으나 데이터의 형식이 방대한 관계로.. 그리고 그러한 여러 데이터 형식이 테스트 코드로 주어지지 않았으므로...
그저 전처리가 제대로 되지 않은 데이터를 발견하면 그때 또 코드를 추가해주는 식으로 해야할 거 같다.

// ● 와 : 사이의 한글 제외
let step1 = data.replace(/●([^:]+):/g, "");

// : 와 - 사이의 한글 제외
step1 = step1.replace(/-.*:/, "").trim();

// 각 식재료와 그람수
const detail = step1.split(", ");

// 괄호 안의 한글 제외
const step2 = step1.replace(/\([^)]+\)/g, "");

...

내가 필요한 정보인 각 재료명 / 각 재료의 그람수를 return 하도록 필터링 해줬다.

메뉴얼의 경우에는 https://jeeumu.tistory.com/253 이와 같이 필터링 해주었다.

여기서 필요한 정보만 빼내서 저장한다

const filterRecipeList = recipeList.map((recipe) => ({
    id: recipe.RCP_SEQ,
    menuName: recipe.RCP_NM,
    menuImage: recipe.ATT_FILE_NO_MK,
    ingredients: ingredientsFiler(recipe.RCP_PARTS_DTLS),
    recipeInfo: manualFilter(recipe),
    menuTip: recipe.RCP_NA_TIP.split("."),
}));
const recipeListCount = recipeList.length;

필요한 정보는 아래와 같다.

id : recipe id
menuName: 메뉴명
menuImage: 대표이미지
ingredients: 재료
recipeInfo: 레시피
menuTip: 메뉴 

각 레시피 순서마다 사진도 제공해주는데 제공해주는 사진이 진짜 너무!!!!!! 미니 아이콘 크기정도로 작아서 사용하지 않기로 했다ㅜㅜ

공공 API에서 필요한 정보만 빼내면

이렇게 원하는 정보만 가져온 것을 확인할 수 있다.


해당 공공 API를 사용하면서 아쉬운 점

1. 여러 형식에 대한 테스트 코드가 없어서 전처리가 제대로 되지 않은 데이터를 발견할 때마다 코드를 추가해줘야함
2. 레시피 순서마다 제공해주는 사진이 너무 작아서 사용하지 못함