외부 API 이용하기 - axios

송철진·2023년 5월 18일
0

Toy Project

목록 보기
6/10

내가 궁금했던 것은

14가지 지표로 깃허브 활동 점수를 랭크로 매길 수 있는 Let's git it사이트에서 종종 눈에 띄는 유저명이나 '설마 있겠어?' 싶은 특이한 유저명을 검색을 하곤 했다. 그러다 rankerId가 2000명을 넘길 무렵 challenger의 수가 고작 20명 남짓인 것에 의문이 들었다. 일일이 입력하는 수작업 없이 top 100을 모두 challenger로 만들 수 있을까? 외부API를 사용하는 방법은 무엇일까?

챗지피티 선생에게 물어보며 다음과 같이 소스코드를 만들게 되었다.
깃허브 유저명은 영어, 숫자, 하이픈('-')을 쓸 수 있지만 단순히 영어철자만 반복하기로 했다.

소스코드

x~z로 시작하는 영어소문자 단어이며 길이가 3인 username의 조회:

const fs = require("fs");
const axios = require("axios");

async function getUsernames() {
  const baseUrl = "https://api.lets-git-it.online/ranks/";
  const validUsernames = [];
  const invalidUsernames = [];

  for (let i = 120; i <= 122; i++) {
    for (let j = 97; j <= 122; j++) {
      for (let k = 97; k <= 122; k++) {
        const username = String.fromCharCode(i, j, k);
        const url = baseUrl + username;
        try {
          const response = await axios.get(url);
          if (response.data) {
            await validUsernames.push(username);
          } else {
            await invalidUsernames.push(username);
          }
          console.log(username);
        } catch (error) {
          continue;
        }
      }
    }
  }
  return { validUsernames, invalidUsernames };
}

getUsernames()
  .then((usernames) => {
    const logText = `valid: ${usernames.validUsernames.join(", ")}\n${
      usernames.validUsernames.length
    }\ninvaild: ${usernames.invalidUsernames.join(", ")}`;
    fs.writeFile("log.txt", logText, (error) => {
      if (error) {
        console.error(error);
      } else {
        console.log("유저명이 성공적으로 log.txt에 저장되었습니다.");
      }
    });
  })
  .catch((error) => {
    console.error(error);
  });

실행 결과

  • top 100
    현재 rankerId가 6800대인 것과 nodejs 유저가 그새 diamond에서 challenger로 변한 것 등으로 미루어보아 tier는 일정 점수 기준이 아니라 상위 n%를 기준으로 주어지는 것으로 추측된다. 즉 username을 1만개 이상 조회하면 top 100이 모두 challenger가 될 것이다.

  • log.txt

  • console

Today I Learn

valid.length: 1686개?

3×26×26=2028개 여야 하는데 왜 기록된 단어는 1700여개 뿐일까?
validUsernamesinvalidUsernames를 구분하는 조건을 response.data가 빈문자열, undefined 등 falsy 값 여부로 작성했다.
어떤 error로 catch된 단어는 누락된 것으로 보인다

catch 블록 안에 continue
try-catch 문은 예외가 발생할 수 있는 코드 블록을 감싸고, 예외가 발생하면 catch 블록 안의 코드가 실행됩니다. continue 문은 반복문에서 현재 반복을 중지하고(해당 유저의 검사를 건너뜀) 다음 반복(다음 유저에 대한 검사)으로 넘어가는 역할을 합니다.

axios란?

Node.js와 브라우저에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리로서 HTTP 요청을 보내고 응답을 받을 수 있다.

axios.get(url)
  .then((response) => {
    // 요청 성공 시 처리할 로직
    console.log(response.data);
  })
  .catch((error) => {
    // 요청 실패 시 처리할 로직
    console.error(error);
  });
axios.post(url, data)
  .then((response) => {
    // 요청 성공 시 처리할 로직
    console.log(response.data);
  })
  .catch((error) => {
    // 요청 실패 시 처리할 로직
    console.error(error);
  });

fs.writeFile()

실행한 username 데이터를 log.txt파일에 저장하기 위해 사용했다
2번째 argument로 받을 data를 객체 자체로 할당했더니 오류가 발생했다.
"data" 인수는 문자열이거나 Buffer, TypedArray 또는 DataView의 인스턴스여야 한다.

getUsernames()
  .then((usernames) => {
	const logText = usernames;
  	fs.writeFile("log.txt", logText, (error)=>{})
  })
  .catch((error)=>{})

TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received an instance of Object
at Object.writeFile (node:fs:2160:5)
at /Users/user/Desktop/test00/app.js:39:8
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_INVALID_ARG_TYPE'
}

문법

fs.writeFile(file, data, options, callback)
  • file: 데이터를 저장할 파일의 경로와 이름을 지정합니다.
  • data: 파일에 저장할 데이터를 지정합니다.
  • options (선택사항): 인코딩 및 기타 옵션을 지정할 수 있는 객체입니다. 기본값은 utf8입니다.
  • callback: 파일 저장 작업이 완료된 후 실행할 콜백 함수입니다. 콜백 함수는 error 매개변수를 통해 에러 정보를 받습니다.

const fs = require('fs');
const data = 'Hello, World!';

fs.writeFile('log.txt', data, (error) => {
  if (error) {
    console.error(error);
  } else {
    console.log('데이터가 성공적으로 log.txt에 저장되었습니다.');
  }
});

String.fromCharCode()

MDN 문서
UTF-16 코드 단위 시퀀스에서 생성된 문자열을 반환한다

const s = String.fromCharCode(189, 43, 190, 61) 
console.log(s) // "½+¾="
profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글