
다리는 놓아줄 수 없기에, 놓는 법을 배포하기로 했다 ── 열쇠가 필요 없는 GAS 중계기를 GitHub에 공개한 이야기
요약
Excel VBA에서 API 키 노출 없이 YouTube Data API를 호출할 수 있도록 돕는 GAS(Google Apps Script) 중계기 제작 및 배포 과정을 다룹니다. API 호출 최적화와 재시도 로직을 통해 성능을 개선하고, 보안을 위해 중계기 설치 방법을 공유하는 데 초점을 맞춥니다.
핵심 포인트
- API 키를 코드에 적지 않고 GAS 권한을 활용하는 보안 설계
- 다단계 API 호출을 1회 왕복으로 압축하여 처리 속도 약 40% 개선
- 일시적 에러 방지를 위한 최대 3회 재시도 로직 구현
- 사용자별 독립적인 중계기 설치를 통한 API 할당량 오남용 방지
고백부터 시작하겠습니다. 이 연재는 본래, 코드 실물을 공개하면서 써 내려갈 계획이었습니다. 그런데 되돌아보니, 최근에는 이야기뿐이었고 GitHub에 새로운 것을 한동안 올리지 못했습니다. 쓰고 싶은 이야기가 계속되었다고 하면 듣기에는 좋겠지만, 실물을 기다려 주신 분들께는 죄송한 말씀입니다.
오늘은 오랜만에 실물이 있습니다.
Excel VBA에서, API 키를 어디에도 적지 않고 YouTube Data API를 호출하기 위한 중계기(GAS 웹 앱)입니다. 지난번, 잠들어 있던 YouTube 목록 엑셀 파일이 이 중계기로 되살아난 이야기를 썼습니다.
이번에는 그 후속편으로, 그 중계기를 배포 가능한 형태로 완성하여 공개하기까지의 이야기와, 그리고 같은 방법을 옆 동네 서비스인──Google의 Gemini──에 시도해 보았으나 통하지 않았다는 검증의 현주소에 대한 이야기입니다.
- GAS 중계기를 GitHub에 공개했습니다. 주인공은 중계기 코드 약 140줄이며, Excel 파일은 「활용 예시」로서 동봉되어 있습니다.
- 다만 배포하는 것은 중계기 그 자체가 아니라, 만드는 법입니다. 설치한 중계기의 URL과 비밀번호는 설치한 본인 전용이며, 타인에게 배포하면 그 사람의 API 할당량이 전대(re-selling)되어 버리기 때문입니다.
- 공개 전 마무리 작업으로, 파일에 남아 있던 다단계 API 호출을 전부 1회 왕복으로 압축했습니다. 최신 50건 취득 시 실측 4.49초 → 2.74초가 되었습니다.
- GAS는 드물게 일시적인 에러를 반환합니다. **최대 3회 재시도하는 망(net)**을 넣었더니, 가끔 발생하는 헛스윙이 사라졌습니다.
- 같은 「열쇠를 없애는」 방법을 Gemini에 시도했으나, 승인 화면에서 문전박대를 당했습니다. YouTube와 Gemini는 인증 설계가 다릅니다.
- Gemini 무료 할당량의 실측은 하루 20회입니다. 그럼에도 Excel과 조합할 수 있는 길을 현재 검증하는 중입니다.
리포지토리의 내용은 5가지뿐입니다.
vba-gas-relay/
README.md ← 설치 절차(약 5분)와 주의사항
gas/relay.gs ← 중계기 본체(약 140줄)
...
중계기의 창구는 3가지가 있습니다.
| 호출 방식 | 역할 |
|---|---|
?tk=…&q=channels?part=… | 범용 중계. API URL을 그대로 전달함 |
?tk=…&mode=latest&channelId=UC… | 최신 50건을 GAS 측에서 모두 수집하여 1회 왕복으로 반환 |
?tk=…&mode=list&channelId=UC… | 채널의 모든 영상을 모두 수집하여 1회 왕복으로 반환 |
구조는 지난번에 쓴 대로입니다. GAS는 YouTube Data API를 표준으로 탑재하고 있어, 키 취득이나 카드 등록도 필요 없습니다. 이를 웹 앱으로 공개하면 URL이 하나 생성되고, VBA에서 그 URL을 호출합니다. 인증은 GAS가 설치한 본인의 Google 계정 권한으로 수행합니다. API 키는 파일에도, GAS에도 존재하지 않습니다.
Excel 파일의 경우, 채널을 지정하면 모든 영상의 제목·조회수·길이·게시 일시를 목록화하는 자작 파일의 공개 버전입니다. 시트의 M1 셀에 채널 ID를 쓰고 버튼을 누르기만 하면 됩니다. 시트를 복제하면 감시할 채널을 얼마든지 늘릴 수 있습니다. 중계기가 어떻게 활용되는지를 보여주는 동작하는 예시라는 위치를 가집니다.
공개 설계에서 가장 고민했던 부분은 여기였습니다.
이 중계기는 말하자면 Excel과 Google 사이에 놓는 다리입니다. 그리고 다리는 놓은 본인만이 건널 수 있도록 만들어져 있습니다. 중계기 URL(주소)과 비밀번호(암호)를 타인에게 알려주면, 그 사람의 통신이 전부 이 다리를 건너게 됩니다. 즉, 자신의 Google 계정 API 할당량이 타인에게 사용되는 결과가 되기 때문입니다.
그래서 배포하는 것은 다리가 아니라, 다리를 놓는 방법입니다. README에 설치 절차를 적어 두었습니다. 소요 시간은 약 5분입니다.
- script.new에서 GAS 프로젝트를 생성
relay.gs를 통째로 붙여넣고, 맨 앞의TOKEN을 직접 정한 비밀번호로 변경appsscript.json을 교체 (읽기 전용 권한 지정)- 웹 앱으로 배포
- 생성된 URL과 비밀번호를 파일의 VBA 상단 2줄에 작성
Private Const GAS_URL As String = "" ' 중계기의 URL (주소)
Private Const GAS_TOKEN As String = "" ' 중계기에 작성한 것과 동일한 비밀번호 (암호)
흥미롭게도, 이렇게 URL과 비밀번호를 '본인용입니다, 배포하지 마세요'라고 적어두면, 공개물 그 자체가 키 관리의 교재처럼 되어갑니다. 세상에는 API 키를 코드에 직접 작성(hard-coding)한 채로 공개된 리포지토리가 산더만 있고, 그것은 사고입니다. 이것은 그 반대──키를 어디에도 적지 않기 위한 도구를, 키 대신 무엇을 지켜야 하는지에 대한 주의사항과 함께 배포하는 형태가 되었습니다.
공개하려면 본인용 상태로는 내놓을 수 없습니다. 세 가지 마무리 작업이 필요했습니다.
첫 번째는 속도입니다. 지난 글에서 "루프를 GAS 측으로 옮겨 왕복 56회를 1회로 만들었더니, 107초가 13.8초가 되었다"라고 썼습니다. 다만, 그것은 전체 동영상 목록이라는 간판 기능만의 이야기였고, 다른 매크로는 다단계 호출(multi-step call) 방식 그대로였습니다. 최신 50건을 가져오는 것은 채널 정보 → 동영상 ID → 동영상 상세 정보라는 3번의 왕복이 필요합니다. 중계기는 왕복 1회당 약 2초의 통행료를 받으므로, 3번 왕복하면 그것만으로도 6초급이 됩니다.
공개 전에 이것을 전부 통합했습니다. 중계기에 mode=latest라는 창구를 추가하여, 3번 왕복할 분량의 작업을 GAS 측에서 끝내고, 정제된 데이터를 1번의 왕복으로 반환하게 했습니다. "최근 3일 치만"과 같은 날짜 필터링도 GAS 측에서 처리하여 필요한 행만 받습니다.
실측 결과입니다 (2026년 8월, 동일 채널에서 측정).
| 작업 | 통합 전 | 통합 후 |
|---|---|---|
| 최신 50건 가져오기 | 4.49초 (3회 왕복) | 2.74초 (1회 왕복) |
| ... |
최신 50건에 2.7초. 나머지 차이는 거의 GAS를 1회 경유하는 고정 비용이므로, 이 정도가 한계치(floor)라고 생각합니다. 전체 동영상의 경우 개수에 비례하는 시간이 걸리며, 이는 동영상이 2,000개 있다면 늘어나는 성질의 것입니다.
왕복 횟수가 속도를 결정한다──지난번에 파악한 이 원리를, 이번에는 북(book)의 모든 매크로에 적용했다는 뜻이 됩니다.
두 번째는 안정성입니다. 계속 사용하다 보면 가끔 데이터 취득이 **말없이 헛스윙(empty miss)**하는 경우가 있었습니다.
정체는 GAS의 특성입니다. GAS의 웹 앱은 아주 드물게 일시적인 404 오류나 HTML 에러 페이지를 반환할 때가 있습니다. 이 코드는 1회 요청 후 실패하면 그대로 끝나는 구조였기에, HTML이 반환되면 데이터로 읽을 수 없어 조용히 헛스윙을 하고 있었던 것입니다.
그물을 쳤습니다. 정상적인 응답이 올 때까지 최대 3회, 2초를 기다렸다가 다시 요청하는 단순한 그물입니다.
For tryN = 1 To 3
http.Open "GET", GAS_URL & "?tk=" & GAS_TOKEN & "&mode=latest&channelId=" & channelId, False
http.Send
...
정상적일 때는 1회 만에 빠져나오므로 속도는 변하지 않습니다. 이것을 넣은 뒤로는 체감상 헛스윙이 발생하지 않게 되었습니다. README에도 "직접 만들 때도 이 그물(재시도 로직)은 넣어두는 것을 추천합니다"라고 적어두었습니다. 지난번에 썼던 ServerXMLHTTP 이야기(MSXML2.XMLHTTP는 GAS의 리다이렉트를 거부함)와 더불어, 이 중계 방식의 2대 함정이라고 생각합니다.
세 번째는 배포의 예법입니다. 공개 버전의 북은 GAS_URL과 GAS_TOKEN을 비워두었습니다. 그렇다면 비워둔 채로 두면 어떻게 될까요?
기존 방식대로 "자신의 API 키를 붙여 직접 호출하는" 방식으로 자동으로 전환됩니다. 통신이 모두 통과하는 함수의 입구에 "GAS URL이 설정되어 있다면 목적지를 교체한다"라는 분기문이 있는, 지난번에 작성한 구조 덕분입니다. 중계기를 구축하는 것은 번거롭지만 API 키는 가지고 있는 분들은 키를 붙이면 동일한 북이 그대로 작동합니다. 두 가지 길 모두 살아있는 것이 이 공개 버전의 사양입니다.
공개 전 검수에서는, 배포 파일의 복사본에 제 중계기 URL과 비밀번호를 작성──즉, 받는 사람과 동일한 절차를 밟아 모든 기능을 실기에서 확인했습니다. 최신 50건 2.74초, 전체 동영상 1,388개 12.58초, 검색, 즐겨찾기. 이 수치는 검수 당시의 것입니다.
자, 이제부터는 현재 진행형 이야기입니다.
YouTube에서 열쇠를 없앨 수 있었다면, 생성형 AI (Generative AI)에서도 없앨 수 있지 않을까. 즉, Google의 Gemini를 API 키 없이 Excel에서 호출할 수 없을까. 같은 방식의 다리 놓기를 옆에 있는 강을 향해 시도해 보았습니다.
결론부터 말하자면, 같은 방법은 통하지 않았습니다.
GAS가 자신의 권한으로 API를 호출하려면, 해당 서비스의 OAuth 스코프 (OAuth Scope, 권한의 명찰 같은 것)가 필요합니다. YouTube에는 그것이 있었습니다. Gemini용 스코프를 지정해 보았더니, 승인 화면에서 「Error 400: invalid_scope」──그런 명찰은 존재하지 않는다며 문전박대를 당했습니다. YouTube API는 OAuth로도 호출할 수 있는 설계이고, Gemini API는 기본적으로 키(Key)로 호출하는 설계입니다. 같은 Google이라도 강의 형태가 달랐던 셈입니다.
따라서 Gemini에서는 열쇠 그 자체를 없앨 수는 없습니다. 여기서 현재 상황을 솔직하게 나열하겠습니다.
API 키를 발급받았습니다. 무료 범위의 실측 결과, 사용할 수 있는 모델은 gemini-2.5-flash뿐이며, 하루 20회입니다. 일본 시간 기준 16시경에 리셋됩니다. 속도는 한가할 때 VBA에서 직접 호출 시 평균 0.72초로 양호하지만, 혼잡할 때는 2~8초까지 늘어납니다 -
키를 운반하는 중계기는 작동했습니다. GAS 중계를 통해 일본어 왕복까지 확인을 마쳤습니다. 다만 이 방식은 열쇠가 없어진 것이 아니기에, YouTube 때와 같은 「배포 가능한 형태」로는 아직 되지 않았습니다 -
조사하여 알아낸 점으로서, Gemini의 채팅 버전 유료 계약을 가지고 있더라도 API의 할당량은 별개입니다. 계약한다고 해서 VBA에서 마음껏 호출할 수 있는 것은 아닙 $-
또 다른 길로서, API를 사용하지 않고 브라우저의 Gemini를 자동 조종하는 실험도 진행했습니다. 프롬프트를 보내고 답변을 받을 때까지 화면 없이 실측한 결과 14.3초였습니다. 하루 20회의 벽은 이 방식에는 없습니다.
요컨대, Google의 Gemini와 Excel VBA를 조합할 수 있을지 현재 검증하는 중입니다. 열쇠는 없앨 수 없고, 무료 범위는 얇습니다. 그래도 몇 가지 길이 있다는 것까지는 알게 되었습니다──오늘은 그런 중간 보고까지입니다. 연구가 형태를 갖추면 다시 결과물과 함께 글을 쓰겠습니다.
마지막으로, 조금만 더 큰 그림을 그려보겠습니다.
이번에 공개한 중계기는 전송 대상이 YouTube로 향해 있을 뿐입니다. GAS가 표준으로 가지고 있는 서비스는 이 외에도 많아서, Gmail도, Drive도, Calendar도, 번역도, 같은 약 140줄의 형식으로 Excel에 도착하게 되는 원리가 됩니다. 배포된 GAS는 URL을 가집니다. URL은 VBA에서 호출할 수 있습니다. 이 두 가지가 성립하는 한, GAS는 Excel에서 Google 서비스군으로 향하는 입구가 될 수 있습니다.
이 부분은 솔직히 아직 이론일 뿐입니다. 실물이 있는 것은 YouTube와 검증 중인 Gemini뿐입니다. 다만, 다리를 놓는 방법은 한 번 익혀두면 재사용할 수 있습니다. 강은 앞으로 하나씩 건너갈 생각입니다.
관례에 따라 분류합니다.
사실: 리포지토리를 공개한 것 (구성 방식은 본문과 같음). 최신 50건 취득 시 3회 왕복 4.49초 → 1회 왕복 2.74초, 최근 3일치 추출 시 시트당 2.10초, 전체 동영상 1,388개가 12.58초라는 점 (2026년 8월 실측). GAS가 드물게 일시적인 404 또는 HTML 에러 페이지를 반환하는 것 (실제로 발생함). Gemini용 OAuth 스코프 지정이 「Error 400: invalid_scope」로 거부되는 것 (실제 승인 화면에서 확인). gemini-2.5-flash의 무료 범위가 하루 20회이며, 초과 후 429 에러가 반환되는 것 (실측). 브라우저 자동 조종의 왕복이 화면 없이 14.3초였다는 것 (실측).
견해: 최신 50건의 2.7초를 「거의 바닥(최저치)」으로 보고 있다는 점 (고정비 구조로부터의 추측입니다). 재시도 망(Retry net)을 통해 헛스윙이 사라졌다는 체감 (사라진 횟수를 직접 센 것은 아닙니다). 「같은 형식으로 Gmail도 Drive도 도착한다」는 YouTube에서 성립한 원리의 연장선이며, 아직 실물을 만들지는 않았습니다.
- 설치한 중계기(Relay)의 URL과 비밀번호는 설치한 본인 전용입니다. 이를 배포하면 자신의 API 할당량이 타인에 의해 사용됩니다. 리포지토리(Repository)에서 배포하는 것은 만드는 방법이지, 누군가의 중계기가 아닙니다. 비밀번호는 책을 펼치면 읽을 수 있는 곳에 적는 방식입니다.
유출되어도 공개 데이터의 읽기만 가능한 구성(읽기 전용 권한 및 엔드포인트 허용 목록)을 전제로 합니다. 샘플 북(Sample book)은 URL과 키를 입력하지 않은 채로 취득 버튼을 누르면 아무런 메시지 없이 0건으로 종료됩니다. 에러 표시는 구현하지 않았습니다. 먼저 사용 설명서 시트의 「연결 설정」을 확인해 주세요. 키 직접 삽입 방식(방식 B)의 코드는 이전에 실제로 사용하던 것을 그대로 남겨두었으나, 공개 버전에서의 연속 실측은 중계 방식(방식 A)으로 진행했습니다. 방식 B는 새로운 키를 통한 재실측까지는 수행하지 않았습니다. - Gemini 무료 할당량 수치는 2026년 8월 시점, 제 키를 이용한 실측값입니다. 할당량 값은 변경될 수 있습니다.
- GAS(Google Apps Script) 무료 할당량(YouTube API 환산 시 1일 1만 유닛)과 스트리밍 미지원에 관한 내용은 지난 기사와 동일합니다.
이 기사의 내용은 영상으로도 정리되어 있습니다. 본문의 삽화는 원래 이 영상을 위해 그린 것입니다.
오랜만에 실물을 배치할 수 있었습니다.
자신을 위한 도구를 배포 가능한 형태로 만드는 작업은, 생각보다 설계에 관한 것이었습니다. 속도를 높이는 것은 접는(Folding) 이야기, 안정화하는 것은 그물(Net)의 이야기, 그리고 무엇을 배포하고 무엇을 배포하지 않을지는 다리(Bridge)의 이야기입니다. URL과 비밀번호만은 건네줄 수 없기에, 놓는 법을 전부 적어서 건네준다── 공개의 형태로서, 이것이 가장 이치에 맞는 방법이라고 생각합니다.
강은 아직 몇 개나 더 있습니다.
그럼, 이만.
이라고 일단 마무리했습니다만, 그 후에 이것저것 시도해 보았더니 엄청난 것을 해냈을지도 모르겠습니다.
내일 다시 발표할게요!
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기