항해99의 잔디 기부 캠페인 분석해보기

후추쌈·2024년 12월 31일
0

항해99에서 의미있는 기부 캠페인을 한다는 소식을 인스타를 통해 우연히 접했다.

깃허브에서 잔디의 개수를 가져오고 그만큼 돈으로 환산하여 기부를 한다.


나는 그저 여기에서 깃허브 계정으로 로그인만 했을 뿐인데, 어떻게 내 잔디 개수를 읽을 수 있었는지 궁금했다.
처음에는 스크래핑을 의심하며 개발자 도구를 살펴봤고, GitHub API의 존재를 알게되었다.

우선 GitHub 로그인하고 기부하기 버튼을 누르면 이러한 깃허브 로그인 페이지가 뜬다.
https://github.com/login?client_id=Ov23lialZQGo2M0UxvyK&return_to=%2Flogin%2Foauth%2Fauthorize%3Fclient_id%3DOv23lialZQGo2M0UxvyK
이러한 url로 이동하는데 이때
client_id=Ov23lialZQGo2M0UxvyK 는 GitHub OAuth 앱 설정에서 생성된 클라이언트 ID이다.
return_to=/login/oauth/authorize?client_id=Ov23lialZQGo2M0UxvyK는 인증 후 GitHub가 리디렉션할 URL이다. 로그인을 하면 바로 이 url로 이동하고 이곳에서 code를 반환받고 곧바로 /campaign(우리가 아는 원래 이벤트 페이지)로 이동한다.
인증 후
return_to로 리디렉션되고
code 값을 빼낸 후
/campaign으로 리디렉션된다.

지금까지 이 과정은 code를 얻기 위함인데 이거는 GitHub OAuth 인증 과정에서 발급되는 임시 코드이다. 이 임시 코드는 애플리케이션이 GitHub로부터 액세스 토큰을 요청할 때만 사용된다. 찾아보니 이 임시코드는 한 번만 사용할 수 있고, 유효 기간이 아주 짧다고 한다.

클라이언트에서는 이 쿼리 속 code를 추출하여 백엔드로 보내고 백엔드에서는 GitHub API를 사용해서 내 계정의 잔디 개수를 알아내어 클라이언트로 반환한다.

  useEffect(() => {
    const code = router.query.code;

    if (code && typeof code === 'string') {
      handleGithubCallback(code, {
        onSuccess: (data) => {
          if (data) {
            setTimeout(() => {
              dynamicCampaignRef.current?.scrollIntoView({
                behavior: 'smooth',
              });
            }, 100);
          }
        },
        onError: (error) => {
          console.error('GitHub OAuth Callback Error:', error);
        },
      });
    }
  }, [router.query.code, handleGithubCallback]);

이렇게 url 속 code 값을 추출하고 아래 코드를 보면 /v3/campaign/2024-christmas/contribute?code=${code} 여기를 통해 백엔드 api를 호출한다.

export async function githubCallback(code: string) {
  try {
    return await instanceV2.post(
      `/v3/campaign/2024-christmas/contribute?code=${code}`,
    );
  } catch (error) {
    console.error(error);
    Sentry.captureException(error, {
      tags: {
        location: 'grass-campaign',
        type: 'github-callback',
      },
    });
  }
}

이렇게 호출되어 얻게된 data는 localStorage에 저장된다.

const GITHUB_DATA_KEY = 'github-user-data';
function setStorageData(data: GrassCampaignResponseDto) {
  if (typeof window === 'undefined') {
    return;
  }

  try {
    const expiredAt = Date.now() + ONE_HOUR;
    localStorage.setItem(GITHUB_DATA_KEY, JSON.stringify({ data, expiredAt }));
  } catch (error) {
    console.error('Failed to save data:', error);
    localStorage.removeItem(GITHUB_DATA_KEY);
  }
}
...
  return useMutation({
    mutationFn: githubCallback,
    onSuccess: async (data) => {
...
      setStorageData(data);
...

Application 탭의 Local storage에서 github-user-data을 확인해보면

currentContributionTotalCount: 722020
gitHubUserId: [gitHubUserId]
gitHubUsername: [gitHubUsername]
pixelCount: 8
startPixel: 3396
totalContributionsIn2024: 1415

이러한 형식으로 저장이 되어있는 것을 확인할 수 있다. 이때 이벤트에서 사용되는 내 잔디 개수는 totalContributionsIn2024 이 값이다.

GitHub API를 사용하는 코드는 백엔드에 있기 때문에 확인할 수는 없었지만 이렇게 잔디 정보를 가져와서 보여줄 수 있다는 것을 알 수 있었고, 다음에 내 포트폴리오에 활용해보면 좋을 거 같다.

profile
LEE YENA

0개의 댓글