본문 바로가기
카테고리 없음

AWS Lambda로 서버리스 GitHub Readme Stats 구축하기: AtCoder 티어 배지 제작 과정

by junah201 2026. 10. 28.

GitHub 프로필 README에 프로그래밍 실력과 활동 기록을 시각적으로 보여주는 통계를 추가하면 자신의 개발 경험을 효과적으로 소개할 수 있습니다. 특히 경쟁 프로그래밍 플랫폼인 AtCoder의 레이팅과 참가 기록을 연동하면, 별도의 페이지에 접속하지 않아도 GitHub 프로필에서 주요 정보를 확인할 수 있습니다.

이 글에서는 AtCoder 사용자 데이터를 수집하고 SVG 이미지로 변환하여 GitHub README에 표시하는 프로젝트의 구현 과정을 살펴봅니다. AWS Lambda와 API Gateway를 활용한 서버리스 아키텍처를 기반으로 데이터 수집, HTML 파싱, SVG 디자인, 캐싱, 자동 배포까지 단계별로 설명합니다.

1. GitHub README Stats는 어떤 원리로 동작할까요?

GitHub README Stats는 사용자 정보를 동적으로 수집한 뒤 이미지 형태로 변환하여 제공하는 방식으로 구현할 수 있습니다. 핵심은 서버에서 데이터를 처리하고, 최종 결과를 SVG 이미지로 반환하는 것입니다.

SVG 이미지로 통계를 제공하는 구조

GitHub Readme Stats는 GitHub README에 사용자별 통계를 표시할 때 참고하기 좋은 프로젝트입니다. 일반적인 이미지 파일과 달리 SVG는 XML 기반의 벡터 그래픽 형식이므로 텍스트와 도형을 코드로 구성할 수 있다는 장점이 있습니다.

SVG 내부의 텍스트를 사용자 데이터에 맞게 변경하면 동일한 디자인을 유지하면서 서로 다른 사용자에게 맞춤형 통계를 제공할 수 있습니다. 필요한 경우 CSS 애니메이션을 추가하여 시각적인 효과도 구현할 수 있습니다.

이러한 방식을 활용하면 사용자마다 별도의 이미지를 미리 제작할 필요가 없습니다. 하나의 SVG 템플릿을 준비하고 요청에 따라 데이터를 삽입하면 되기 때문입니다.

요청부터 이미지 출력까지의 처리 과정

서비스의 기본적인 동작 과정은 다음과 같습니다.

  1. 사용자가 자신의 GitHub README에 등록한 이미지 URL을 통해 서버에 요청합니다. 요청에는 AtCoder 사용자명이 포함됩니다.
  2. 서버는 전달받은 사용자명을 이용해 AtCoder에서 필요한 정보를 수집합니다.
  3. 수집한 데이터를 SVG 템플릿에 적용하고, 완성된 이미지를 HTTP 응답으로 반환합니다.
  4. GitHub는 README를 표시하는 과정에서 해당 URL의 SVG 이미지를 불러옵니다.

이 구조에서는 GitHub 자체적으로 통계 데이터를 계산할 필요가 없습니다. 서버가 사용자별 데이터를 처리하고 이미지를 생성하므로, README에 이미지 주소를 등록하는 것만으로 동적인 통계 표시가 가능합니다.

2. AtCoder에서 사용자 데이터를 수집하는 방법

AtCoder의 사용자 정보를 가져오려면 먼저 공개된 API가 있는지 확인해야 합니다. 공식적으로 제공되는 데이터와 사용자 페이지의 HTML을 활용하는 방법을 구분하면 구현 방향을 명확하게 결정할 수 있습니다.

개발자 도구를 이용한 API 확인

먼저 AtCoder의 사용자 프로필 페이지에 접속한 다음 브라우저 개발자 도구를 열었습니다. 네트워크 탭에서 페이지가 불러오는 요청을 살펴보면 사용자 정보가 어떤 방식으로 전달되는지 확인할 수 있습니다.

확인 결과, 필요한 정보가 별도의 API 응답으로 분리되어 제공되기보다는 사용자 정보가 포함된 HTML 문서에 담겨 전달되는 것을 확인했습니다.

HTML을 직접 분석하는 방법은 API를 호출하는 방식보다 구현 과정이 복잡할 수 있습니다. 또한 페이지의 구조가 변경되면 데이터 추출 코드도 수정해야 할 가능성이 있습니다. 따라서 먼저 기존 프로젝트나 관련 개발 자료에서 활용할 수 있는 데이터 엔드포인트가 있는지 조사하는 것이 좋습니다.

AtCoder 사용자 기록 JSON 엔드포인트 활용

관련 프로젝트를 조사하는 과정에서 사용자별 대회 기록을 JSON 형식으로 제공하는 다음 엔드포인트를 확인했습니다.

https://atcoder.jp/users/{사용자명}/history/json

예를 들어 사용자명이 junah라면 다음 주소로 요청할 수 있습니다.

https://atcoder.jp/users/junah/history/json

이 주소에서는 사용자의 대회 참가 이력을 JSON 데이터로 확인할 수 있습니다. 최근 대회 기록을 분석하면 현재 레이팅을 파악하는 데 필요한 정보를 얻을 수 있습니다.

JSON은 HTML보다 구조화된 데이터이므로 프로그램에서 처리하기 편리합니다. 응답을 객체나 배열로 변환한 뒤 필요한 필드에 접근하면 되므로 별도의 HTML 파서가 필요하지 않습니다.

JSON 데이터만으로는 부족한 이유

문제는 해당 엔드포인트가 제공하는 정보의 범위입니다. 대회 이력만으로는 README에 표시하려는 모든 프로필 정보를 충분히 확보하기 어렵습니다.

이번 프로젝트에서 표시하려는 데이터는 다음과 같습니다.

  • AtCoder 사용자명
  • 현재 레이팅 및 티어
  • 현재 레이팅 점수
  • 최고 레이팅 점수
  • 참가한 대회 수

이처럼 여러 종류의 정보를 하나의 배지에 표시하려면 대회 이력뿐 아니라 사용자 프로필에 포함된 다른 정보도 필요합니다.

따라서 부족한 정보를 보완하기 위해 AtCoder 사용자 페이지의 HTML을 직접 파싱하는 방식을 선택했습니다. 다만 HTML 파싱은 페이지 구조에 의존하므로, 서비스 운영 중에도 정상적으로 데이터가 추출되는지 확인할 수 있도록 예외 처리와 테스트를 함께 구성하는 것이 중요합니다.

3. HTML 파싱으로 필요한 정보를 추출하기

사용자 프로필의 HTML 구조를 분석하면 원하는 정보가 어느 영역에 배치되어 있는지 파악할 수 있습니다. 이후 해당 영역에서 텍스트를 추출하여 통계 데이터로 가공하면 됩니다.

프로필 상단 테이블 분석

AtCoder 사용자 페이지의 상단 테이블에는 기본 프로필 정보가 표시됩니다. 페이지 구성에 따라 국가, 생년월일, Twitter ID, Codeforces ID 등 사용자가 입력한 정보를 확인할 수 있습니다.

이 영역은 사용자 프로필의 기본 정보를 확인하는 데 유용합니다. 다만 모든 사용자가 모든 항목을 입력하는 것은 아니므로, 값이 비어 있거나 특정 항목이 존재하지 않는 상황도 고려해야 합니다.

파싱 코드를 작성할 때는 단순히 테이블의 특정 위치에 있는 텍스트를 가져오는 것보다 항목의 이름이나 HTML 구조를 기준으로 값을 추출하는 편이 유지보수에 유리합니다.

프로필 하단 테이블에서 통계 추출하기

하단 테이블은 대회 활동과 관련된 핵심 데이터를 제공하는 영역입니다. 현재 레이팅, 최고 레이팅, 참가 대회 수, 최근 대회 날짜 등의 정보를 확인할 수 있습니다.

수집한 값은 SVG 템플릿에 전달하기 적합한 데이터 구조로 정리합니다. 예를 들어 레이팅 점수는 숫자로 변환하고, 참가 대회 수는 정수로 처리하며, 사용자명은 문자열로 관리할 수 있습니다.

이처럼 데이터 수집과 이미지 생성을 별도의 단계로 분리하면 각각의 기능을 독립적으로 테스트하기도 쉬워집니다.

반드시 고려해야 하는 두 가지 예외 상황

HTML 파싱에서는 정상적인 사용자 페이지뿐 아니라 예상하지 못한 응답도 처리해야 합니다. 특히 다음 두 가지 상황은 필수적으로 고려해야 합니다.

첫 번째는 존재하지 않는 사용자명을 요청하는 경우입니다.

사용자 페이지가 존재하지 않으면 정상적인 프로필 테이블 대신 User not found라는 메시지가 표시될 수 있습니다. 이때 프로그램이 일반 사용자 페이지와 동일한 방식으로 데이터를 추출하면 예외가 발생하거나 잘못된 이미지가 생성될 수 있습니다.

따라서 HTML을 파싱하기 전에 사용자가 실제로 존재하는지 확인하고, 존재하지 않는 경우에는 적절한 오류 응답을 반환하도록 구현해야 합니다.

두 번째는 대회에 한 번도 참가하지 않은 사용자입니다.

AtCoder 계정이 존재하더라도 대회 참가 기록이 없다면 대회 통계를 담은 하단 테이블이 나타나지 않을 수 있습니다. 이 경우 테이블을 무조건 탐색하는 코드는 오류를 발생시킬 수 있습니다.

이를 방지하려면 해당 영역의 존재 여부를 먼저 확인해야 합니다. 대회 기록이 없다면 점수와 참가 횟수를 0으로 표시하거나, 데이터가 없음을 나타내는 기본값을 적용하는 방법을 사용할 수 있습니다.

이러한 예외 처리는 단순히 프로그램의 오류를 방지하는 데 그치지 않습니다. 다양한 상태의 계정에서도 일관된 결과를 제공하기 위한 필수적인 설계 요소입니다.

4. Figma로 SVG 배지 디자인하기

사용자 데이터 수집 기능이 준비되었다면 다음 단계는 정보를 보기 좋게 표현할 디자인을 만드는 것입니다. 데이터가 정확하더라도 시각적인 구성이 복잡하면 GitHub 프로필에서 통계의 가독성이 떨어질 수 있습니다.

Figma를 활용한 레이아웃 설계

이번 프로젝트에서는 UI 디자인 도구인 Figma를 사용해 배지의 레이아웃을 구성했습니다. 사용자명과 레이팅처럼 중요한 정보가 눈에 잘 들어오도록 배치하고, 여러 통계 항목을 구분하여 읽기 쉽게 설계했습니다.

디자인 단계에서는 다음 사항을 고려할 수 있습니다.

  • 사용자명과 현재 레이팅을 명확하게 구분합니다.
  • 최고 레이팅과 대회 참가 횟수는 보조 정보로 배치합니다.
  • 텍스트가 길어지더라도 레이아웃이 쉽게 깨지지 않도록 합니다.
  • GitHub README의 배경과 함께 표시했을 때도 충분한 대비를 유지합니다.

Figma에서 시안을 완성한 다음 이를 SVG 코드로 구현했습니다. SVG는 텍스트와 도형을 코드로 직접 제어할 수 있으므로, 서버에서 사용자별 값을 삽입하기에 적합합니다.

동적 데이터를 SVG에 적용하기

SVG 템플릿을 구성할 때는 디자인 요소와 사용자 데이터를 구분하는 것이 중요합니다. 배경, 테두리, 텍스트 위치와 같은 요소는 고정하고, 사용자명과 레이팅 등 변경되는 값만 동적으로 삽입하는 구조가 효율적입니다.

예를 들어 동일한 템플릿을 사용하더라도 사용자 A에게는 현재 레이팅 800을, 사용자 B에게는 현재 레이팅 1600을 표시할 수 있습니다.

이 방식은 이미지 생성 과정을 단순화하고 여러 사용자에게 동일한 디자인 규칙을 적용할 수 있게 합니다. 또한 SVG의 텍스트와 도형을 활용하면 별도의 이미지 편집 라이브러리 없이도 비교적 가벼운 결과물을 만들 수 있습니다.

단, 외부에서 전달받은 사용자명이나 텍스트를 SVG에 삽입할 때는 특수문자 이스케이프 처리를 적용해야 합니다. 그렇지 않으면 XML 문법이 깨지거나 의도하지 않은 마크업이 포함될 수 있습니다.

5. AWS Lambda 기반 서버리스 아키텍처를 선택한 이유

이번 프로젝트에서는 별도의 상시 실행 서버 대신 AWS Lambda를 이용해 백엔드를 구성했습니다. 요청 빈도가 높지 않은 개인 프로젝트에서는 서버리스 구조가 비용과 운영 부담을 줄이는 데 도움이 될 수 있습니다.

요청량에 맞춰 비용을 관리할 수 있습니다

EC2와 같은 가상 서버를 이용하면 서버를 계속 실행하는 동안 인스턴스 비용이 발생합니다. 반면 AWS Lambda는 함수 실행량과 실행 시간 등을 기준으로 과금되므로, 요청이 드문 서비스에 적합할 수 있습니다.

특히 GitHub README 통계 서비스는 일반적인 웹 애플리케이션과 달리 사용자가 직접 페이지에 접속하기보다는 README를 표시하는 과정에서 이미지 요청이 발생하는 구조입니다.

이러한 특성을 고려하면 트래픽이 적은 초기 단계에서 상시 서버를 운영하기보다 서버리스 환경으로 시작하는 것이 합리적인 선택일 수 있습니다.

다만 서버리스가 언제나 더 저렴한 것은 아닙니다. 요청량, 실행 시간, API Gateway 비용, 캐싱 설정, 데이터 전송량 등에 따라 실제 비용이 달라지므로 배포 후 사용량을 확인하는 것이 좋습니다.

캐싱을 통해 AtCoder 요청을 줄일 수 있습니다

두 번째 이유는 외부 서비스의 데이터를 반복해서 요청하는 문제입니다. 모든 이미지 요청마다 AtCoder 사용자 페이지를 다시 가져오면 동일한 정보를 불필요하게 여러 번 수집하게 됩니다.

이는 응답 시간을 늘릴 뿐 아니라 외부 서비스에 추가적인 요청 부담을 줄 수 있습니다. 따라서 적절한 캐싱을 적용하여 일정 시간 동안 동일한 결과를 재사용하는 것이 중요합니다.

HTTP 응답에 Cache-Control 헤더를 설정하면 브라우저나 중간 캐시가 응답을 저장하도록 유도할 수 있습니다. 하지만 이 방식만으로는 모든 요청에 대한 서버 측 캐싱이 보장되지 않습니다.

이번 프로젝트에서는 API Gateway의 캐싱 기능을 활용하는 방향을 선택했습니다. 이를 통해 캐시가 유효한 동안 동일한 요청에 대해 백엔드 함수가 반복 실행되는 것을 줄일 수 있습니다.

캐시를 설계할 때는 사용자명과 같은 요청 매개변수가 캐시 키에 올바르게 반영되는지 확인해야 합니다. 서로 다른 사용자의 응답이 같은 캐시 항목에 저장되지 않도록 하고, 레이팅 변경 사항이 지나치게 늦게 반영되지 않도록 적절한 TTL(Time To Live)을 설정해야 합니다.

또한 API Gateway의 캐싱 기능은 API 유형과 설정에 따라 사용 가능 여부가 달라질 수 있으므로, 실제 배포 환경에서 지원 범위와 비용을 확인해야 합니다.

6. AWS Lambda와 API Gateway 연결하기

서버리스 구조를 선택했다면 Lambda 함수를 생성하고 API Gateway를 통해 외부 요청을 전달하도록 구성해야 합니다. 여기에 사용자 정의 도메인과 자동 배포 환경을 연결하면 실제로 사용할 수 있는 서비스가 완성됩니다.

Lambda 함수 생성 및 API Gateway 연동

먼저 AWS Lambda에서 SVG 이미지를 생성하는 코드를 실행할 함수를 생성합니다. 이 함수는 사용자명을 입력받고, AtCoder 데이터를 수집한 다음 SVG를 생성하여 반환하는 역할을 담당합니다.

이후 API Gateway를 구성해 외부 HTTP 요청이 Lambda 함수로 전달되도록 연결합니다. 요청 URL에서 사용자명을 읽어 함수에 전달하고, 생성된 SVG를 클라이언트에 반환하도록 설정합니다.

SVG를 정상적으로 표시하려면 응답의 Content-Type도 적절히 설정해야 합니다. 일반적으로 SVG 이미지에는 image/svg+xml을 사용합니다.

또한 오류가 발생했을 때도 적절한 HTTP 상태 코드와 응답을 반환하도록 구성하면 문제를 진단하고 클라이언트에서 처리하기가 쉬워집니다.

사용자 정의 도메인 연결

API Gateway가 제공하는 기본 엔드포인트 대신 별도로 보유한 도메인을 연결하면 주소를 더 간결하게 만들 수 있습니다.

도메인 연결 과정에서는 DNS 레코드와 API Gateway의 사용자 정의 도메인 설정을 함께 확인해야 합니다. CNAME 레코드를 변경하는 것만으로 모든 환경에서 연결이 완료되는 것은 아니며, 도메인 유형과 DNS 제공 업체에 따라 추가 설정이 필요할 수 있습니다.

HTTPS를 사용하려면 인증서도 올바르게 구성해야 합니다. 배포가 완료된 뒤에는 사용자 정의 도메인으로 요청을 보내 SVG 응답이 정상적으로 반환되는지 확인하는 것이 좋습니다.

7. GitHub Actions로 CI/CD 자동화하기

서비스 코드를 수정할 때마다 AWS 콘솔에서 직접 배포하면 작업이 번거롭고 실수할 가능성도 높아집니다. GitHub Actions를 이용하면 저장소에 변경 사항을 반영했을 때 자동으로 배포하도록 구성할 수 있습니다.

코드 변경부터 자동 배포까지

GitHub Actions는 저장소에서 발생하는 이벤트를 기반으로 빌드, 테스트, 배포 등의 작업을 실행하는 자동화 도구입니다.

이번 프로젝트에서는 GitHub 저장소에 코드가 푸시되면 배포 작업이 실행되도록 설정했습니다. 이를 통해 개발 환경에서 수정한 코드를 일일이 수동으로 업로드하지 않고도 AWS Lambda에 반영할 수 있습니다.

일반적인 자동 배포 과정은 다음과 같습니다.

  1. 개발자가 프로젝트 코드를 수정하고 GitHub 저장소에 푸시합니다.
  2. GitHub Actions 워크플로가 실행됩니다.
  3. 필요한 의존성을 설치하고 테스트 및 검증 작업을 수행합니다.
  4. AWS 인증 정보를 이용해 Lambda 함수를 업데이트합니다.
  5. 배포가 완료되면 실제 API 엔드포인트에서 정상적으로 동작하는지 확인합니다.

실제 워크플로에서는 AWS 자격 증명을 코드에 직접 작성하지 않는 것이 중요합니다. GitHub Actions의 Secrets 또는 OIDC 기반 역할 연동 등 안전한 인증 방식을 사용하고, 배포 권한도 필요한 범위로 제한하는 것이 좋습니다.

이러한 CI/CD 환경을 구축하면 반복적인 배포 작업을 자동화하고 코드 변경 사항을 보다 일관되게 운영할 수 있습니다.

8. AtCoder GitHub Readme Stats 직접 사용하기

프로젝트 구현과 배포가 완료되면 실제 GitHub README에서 생성된 배지를 사용할 수 있습니다. 별도의 이미지 파일을 저장할 필요 없이 API 엔드포인트를 이미지 주소로 등록하면 됩니다.

프로젝트 소스코드 확인하기

전체 구현 코드는 GitHub 저장소에서 확인할 수 있습니다.

소스코드를 살펴보면 사용자 데이터 수집, SVG 생성, 서버리스 배포 구조가 어떻게 연결되는지 확인할 수 있습니다. 비슷한 통계 배지를 직접 개발하려는 경우에도 참고 자료로 활용할 수 있습니다.

사용자명으로 배지 생성하기

다음 API 주소에서 your_handle 부분을 실제 AtCoder 사용자명으로 변경하면 해당 계정의 배지를 요청할 수 있습니다.

https://atcoder.junah.dev/v1/generate_badge?name=your_handle

예를 들어 AtCoder 사용자명이 junah라면 다음과 같이 사용할 수 있습니다.

https://atcoder.junah.dev/v1/generate_badge?name=junah

이 URL을 브라우저에서 열어 이미지가 정상적으로 생성되는지 확인한 다음, GitHub 프로필 README의 이미지 주소로 등록하면 됩니다.

README에서는 다음과 같은 Markdown 문법을 사용할 수 있습니다.

![AtCoder Readme Stats](https://atcoder.junah.dev/v1/generate_badge?name=junah)

사용자명만 변경하면 다른 계정의 통계를 요청할 수 있다는 점이 이 방식의 장점입니다. 다만 API가 실제로 제공하는 데이터와 배지 디자인은 배포된 코드의 구현 내용에 따라 달라질 수 있습니다.

9. 서버리스 통계 서비스의 확장 가능성

이번 프로젝트는 외부 플랫폼의 데이터를 수집하고 SVG로 변환하여 제공하는 작은 서비스이지만, 여러 웹 서비스에서 활용할 수 있는 설계 원칙을 담고 있습니다.

다른 플랫폼의 통계 배지로 확장하기

동일한 구조는 AtCoder 이외의 서비스에도 응용할 수 있습니다. 특정 사용자의 활동 데이터를 수집할 수 있는 API가 있다면 데이터를 가공하고 SVG 템플릿에 반영하는 방식으로 다양한 통계 배지를 제작할 수 있습니다.

예를 들어 GitHub 활동량, 경쟁 프로그래밍 기록, 프로젝트 기여 현황 등 정형화된 데이터를 시각화하는 서비스로 확장할 수 있습니다.

이때 데이터 수집 로직과 SVG 렌더링 로직을 분리하면 새로운 플랫폼을 추가하기도 쉬워집니다. 데이터 제공 방식이 달라져도 최종 출력 템플릿을 그대로 재사용할 수 있기 때문입니다.

안정적인 운영을 위한 추가 고려 사항

실제 운영 환경에서는 단순히 이미지를 생성하는 기능 외에도 몇 가지 요소를 점검해야 합니다.

  • 캐싱 정책: 데이터가 갱신되는 주기를 고려하여 적절한 캐시 만료 시간을 설정합니다.
  • 오류 처리: 존재하지 않는 계정, 데이터 형식 변경, 외부 서비스 장애에 대응합니다.
  • 요청 제한: 비정상적으로 많은 요청이 발생해 비용이 증가하지 않도록 적절한 제한 정책을 검토합니다.
  • 모니터링: Lambda 실행 오류, 응답 시간, 요청량 및 비용을 정기적으로 확인합니다.
  • 보안: 사용자 입력값을 검증하고, SVG에 삽입되는 문자열을 안전하게 처리합니다.
  • 유지보수: AtCoder 페이지의 HTML 구조가 변경되었을 때 파싱 코드가 정상적으로 작동하는지 확인합니다.

특히 HTML 파싱 방식은 외부 페이지의 구조 변경에 영향을 받을 수 있으므로, 장기적으로 운영할 계획이라면 오류 감지와 테스트를 함께 구성하는 것이 좋습니다.

AWS Lambda와 SVG로 만드는 나만의 GitHub 통계 배지

AtCoder Readme Stats 프로젝트는 외부 서비스에서 데이터를 수집하고, 이를 SVG 이미지로 변환한 뒤 서버리스 환경에서 제공하는 과정을 보여줍니다. 사용자별 데이터를 동적으로 처리하므로 정적인 이미지보다 유연하게 통계를 표시할 수 있으며, GitHub README와도 간단하게 연동할 수 있습니다.

AWS Lambda, API Gateway, SVG, GitHub Actions를 조합하면 상시 실행 서버를 직접 관리하는 부담을 줄이면서 데이터 수집부터 자동 배포까지 하나의 흐름으로 구성할 수 있습니다.

이러한 접근 방식은 단순한 프로필 배지를 넘어 외부 API 데이터를 시각화하는 다양한 개인 프로젝트에도 적용할 수 있습니다. 직접 소스코드를 확인하고 구조를 응용해 자신만의 통계 서비스를 만들어 보시기 바랍니다.