개인 프로젝트를 구상하다가 재미있고 애정이 가는 프로젝트를 해보고 싶었습니다. 삶에 유익한 Open API도 많지만, 메이플스토리 Open API를 활용하여 maple.gg 같은 종합 통계 페이지를 만들어보기로 했습니다.
☑️ 목표

우선 메인 페이지에 카테고리별 랭킹 데이터를 노출시켜 보는 것부터 시작했습니다. 메이플스토리 Open API를 통해 제공되는 다양한 데이터를 활용하며, 첫 번째로 종합 랭킹(overall)과 유니온 랭킹(union) 데이터를 가져오는 기능을 구현했습니다.
☑️ 메이플스토리 Open API 소개
메이플스토리 Open API는 Nexon Open API 문서를 통해 제공되며, 유저 데이터를 활용할 수 있도록 다양한 엔드포인트를 제공합니다.
API Key 발급 및 환경 변수 설정
먼저, 문서에 따라 Nexon Developer Center에서 API Key를 발급받고 프로젝트의 .env 파일에 설정했습니다.
REACT_APP_MAPLE_KEY=YOUR_API_KEY_HERE
REACT_APP_BASE_URL=https://open.api.nexon.com
☑️ 랭킹 데이터 가져오기
API 사용 예제는 문서에서 아래와 같은 형태로 제공됩니다.
const API_KEY = "YOUR API KEY HERE";
const characterName = "CHARACTER NAME";
const urlString = "https://open.api.nexon.com/heroes/v1/id?character_name=" + characterName;
fetch(urlString, {
headers: {
"x-nxopen-api-key": API_KEY,
},
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
☑️ 랭킹 데이터 Fetch 구현
저는 우선 종합 랭킹(overall)과 유니온 랭킹(union) 데이터를 가져와 메인 컴포넌트에 렌더링하도록 구현했습니다.
초기 구현 코드
아래는 Main 컴포넌트에서 각각의 데이터를 가져오는 초기 코드입니다.
useEffect(() => {
const overallFetch = async () => {
try {
const response = await fetch(urlString, {
headers: {
"x-nxopen-api-key": API_KEY || "",
},
});
if (!response.ok) {
throw new Error(`error: ${response.status}`);
}
const data = await response.json();
setOverallRanking(data.ranking);
} catch (error) {
console.error(error);
}
};
const unionFetch = async () => {
try {
const response = await fetch(urlString, {
headers: {
"x-nxopen-api-key": API_KEY || "",
},
});
if (!response.ok) {
throw new Error(`error: ${response.status}`);
}
const data = await response.json();
setUnionRanking(data.ranking);
} catch (error) {
console.error(error);
}
};
overallFetch();
unionFetch();
}, [urlString]);
☑️ 코드 단순화 및 개선
하지만 위 코드는 중복된 데이터 요청 로직이 포함되어 있어, 데이터를 더 많이 가져와야 하는 경우 유지보수가 어려워질 수 있습니다. 이를 개선하기 위해 공통된 로직을 함수로 추출하고 재사용 가능한 방식으로 리팩터링했습니다.
공통 Fetch 함수 추출
먼저, 데이터를 가져오는 공통 로직을 함수로 추출했습니다. 제네릭(Generic) 을 사용해 다양한 데이터 타입을 처리할 수 있도록 구현했습니다.
const fetchRanking = async <T,>(
endpoint: string,
setData: (data: T[]) => void
) => {
try {
const response = await fetch(endpoint, {
headers: {
"x-nxopen-api-key": API_KEY || "",
},
});
if (!response.ok) {
throw new Error(`error: ${response.status}`);
}
const data = await response.json();
setData(data.ranking);
} catch (error) {
console.error(error);
}
};
URL 변수화 및 데이터 요청 단순화
Main 컴포넌트에서 URL을 변수로 관리하여 가독성을 높였습니다. 또한, 공통 Fetch 함수를 호출하여 데이터를 가져오는 로직을 단순화했습니다.
const overallUrl = `${BASE_URL}/ranking/overall?date=${todayDate}&page=1`;
const unionUrl = `${BASE_URL}/ranking/union?date=${todayDate}&page=1`;
useEffect(() => {
fetchRanking<OverallRanking>(overallUrl, setOverallRanking);
fetchRanking<UnionRanking>(unionUrl, setUnionRanking);
}, [overallUrl, unionUrl]);
☑️ 최종 구현 코드
import { FC, useEffect, useState } from "react";
import { getTodayDate } from "../../utils/getTodayDate.utils";
import { OverallRanking, UnionRanking } from "../../types/ranking.types";
import Overall from "../../components/ranking/overall";
import Union from "../../components/ranking/union";
import "./main.style.scss";
const API_KEY = process.env.REACT_APP_MAPLE_KEY;
const BASE_URL = process.env.REACT_APP_BASE_URL;
const fetchRanking = async <T,>(
endpoint: string,
setData: (data: T[]) => void
) => {
try {
const response = await fetch(endpoint, {
headers: {
"x-nxopen-api-key": API_KEY || "",
},
});
if (!response.ok) {
throw new Error(`error: ${response.status}`);
}
const data = await response.json();
setData(data.ranking);
} catch (error) {
console.error(error);
}
};
const Main: FC = () => {
const todayDate = getTodayDate();
const [overallRanking, setOverallRanking] = useState<OverallRanking[]>([]);
const [unionRanking, setUnionRanking] = useState<UnionRanking[]>([]);
const overallUrl = `${BASE_URL}/ranking/overall?date=${todayDate}&page=1`;
const unionUrl = `${BASE_URL}/ranking/union?date=${todayDate}&page=1`;
useEffect(() => {
fetchRanking<OverallRanking>(overallUrl, setOverallRanking);
fetchRanking<UnionRanking>(unionUrl, setUnionRanking);
}, [overallUrl, unionUrl]);
return (
<section id="main">
<h1>Main</h1>
<ul>
<li>
<Overall overallRanking={overallRanking} />
</li>
<li>
<Union unionRanking={unionRanking} />
</li>
</ul>
</section>
);
};
export default Main;'FrontEnd' 카테고리의 다른 글
| [메이플스토리 Open API] React Query로 API 요청 최적화하기 (1) | 2025.01.20 |
|---|---|
| Spotify 프로젝트 기록 일지(1) (1) | 2024.12.23 |