sgcOpenAPI를 통한 GitHub REST API Delphi 클라이언트

GitHub는 어디에 공개된 것과 견주어도 가장 큰 축에 드는 OpenAPI 설명을 유지 관리하고, MIT 라이선스로 배포해요. sgcOpenAPI는 손으로 작성한 GitHub 컴포넌트를 제공하지 않아요. 대신 생성기를 제공해요. api.github.com.json에 명령 한 줄을 실행하면 메서드 1,225개, 그 각각에 타입이 지정된 응답 클래스 하나, 그리고 바로 쓸 수 있는 클라이언트를 돌려주는 GetOpenAPIClient 함수를 담은 Pascal 유닛 하나가 만들어져요.

GitHub + sgcOpenAPI

아래 수치는 현재 설명에 생성기를 실행하고 결과를 컴파일해서 측정한 값이에요. 추정치가 아니에요.

소스 사양

github/rest-api-descriptiondescriptions/api.github.com/api.github.com.json이고 OpenAPI 3.0.3으로 선언되어 있어요. 변환 단계는 필요 없어요.

무엇이 나오나요

813개의 경로가 1,225개의 메서드와 1,134개의 응답 클래스가 되고, 여기에 3,250개의 모델 클래스가 더해져 약 274,000줄짜리 유닛 하나가 나와요.

인증

-a 2로 생성하고 런타임에 Authentication.Token.BearerToken을 설정하세요. 개인 액세스 토큰과 설치 토큰 모두 이 방식으로 처리돼요.

컴파일돼요

생성된 유닛은 RAD Studio 12의 Win32에서 라이브러리 경로에 sgcOpenAPI Source 폴더 말고는 아무것도 없이 깨끗하게 빌드돼요.

생성기 실행하기

GitHub는 같은 설명을 여러 형태로 게시해요. api.github.com.json은 호스팅 서비스를 설명하고 ghes-3.x.json은 GitHub Enterprise Server를 설명해요. 대상으로 삼는 쪽에서 생성하세요.

> sgcOpenAPI.exe -i "api.github.com.json" -o "github.pas" -a 2

File successfully created github.pas

-i는 로컬 파일이나 URL을 받고 JSON과 YAML을 모두 인식해요. -o는 작성할 Pascal 유닛이고, 유닛 이름은 그 파일 이름을 따라요. -a 2는 토큰 인증을 선택하므로 생성된 모든 메서드가 Authorization: Bearer를 보내요. 같은 실행 파일을 매개변수 없이 시작하면 GUI 마법사가 되고, 성공하면 0, 입력 파일이 잘못되면 5, 출력 파일이 잘못되면 6, 문서를 유효한 OpenAPI 3 문서로 바꿀 수 없으면 7로 종료해요.

생성된 .pas를 프로젝트에 추가하고 uses 절에 넣으세요. sgcOpenAPI는 컴포넌트를 등록하지 않고 디자인타임 패키지도 제공하지 않기 때문에, 설치할 컴포넌트가 없어요.

저장소 나열하기

GitHub는 오퍼레이션 id를 repos/list-for-authenticated-user처럼 슬래시와 하이픈으로 써요. 이 문자들은 Pascal 식별자에 들어갈 수 없어서 생성기가 제거하고, 메서드는 reposlistforauthenticateduser로 나와요.

uses
  github;   // 방금 생성한 유닛

procedure TfrmGitHub.btnReposClick(Sender: TObject);
var
  oResponse: TsgcOpenAPI_reposlistforauthenticateduser_Response;
  oRepo: TsgcOpenAPI_repository_Class;
begin
  GetOpenAPIClient.Authentication.Token.BearerToken := txtToken.Text;

  oResponse := GetOpenAPIClient.reposlistforauthenticateduser(
    'private', 'owner', 'all', 'full_name', '', 100, 1);
  try
    if oResponse.IsSuccessful then
    begin
      for oRepo in oResponse.Successful.Items do
        memoLog.Lines.Add(oRepo.Full_name + '  ' + oRepo.Description);
    end
    else
      memoLog.Lines.Add(IntToStr(oResponse.ResponseCode) + ' ' +
        oResponse.ResponseError);
  finally
    oResponse.Free;
  end;
end;

배열을 반환하는 엔드포인트는 Successful이 타입이 지정된 Items를 가진 TsgcOpenAPIArray 자손인 응답을 받아요. 여기서는 TArray<TsgcOpenAPI_repository_Class>예요. 기본 URL은 servers 항목에서 나오기 때문에 생성된 생성자가 이미 https://api.github.com을 설정해 둬요. 페이지 매김은 감춰지지 않아요. aPer_pageaPage는 평범한 인자이고 페이지 순회는 직접 해요.

소문자 이름이 거슬린다면 -m 1로 생성해서 오퍼레이션 요약에서 메서드 이름을 짓거나, -m 2로 엔드포인트에서 이름을 짓게 하세요.

이슈 생성하고 풀 리퀘스트 나열하기

경로 매개변수는 문서가 선언한 순서대로 앞쪽 인자로 들어와요. 요청 본문은 문자열로 들어오는데, 그 이유는 아래에 있어요.

var
  oIssue: TsgcOpenAPI_issuescreate_Response;
  oPulls: TsgcOpenAPI_pullslist_Response;
begin
  oIssue := GetOpenAPIClient.issuescreate('octocat', 'Hello-World',
    '{"title":"Memory leak in the HTTP/2 reader",' +
    '"body":"Repro steps: ...","labels":["bug","http2"]}');
  try
    if oIssue.IsSuccessful then
      memoLog.Lines.Add('filed issue #' +
        IntToStr(oIssue.Successful.Number) + ' ' + oIssue.Successful.Html_url)
    else
      memoLog.Lines.Add(oIssue.Error422._message);
  finally
    oIssue.Free;
  end;

  oPulls := GetOpenAPIClient.pullslist('octocat', 'Hello-World',
    'open', 'updated');
  try
    memoLog.Lines.Add(IntToStr(oPulls.ResponseCode));
  finally
    oPulls.Free;
  end;
end;

각 응답 클래스는 Successful과 함께 문서가 선언한 상태 코드마다 속성 하나를 갖고 있어요. 그래서 호출이 실패했을 때 Error304, Error401, Error403, Error422를 읽을 수 있어요. GitHub가 이름 있는 스키마로 설명한 상태는 클래스가 되고, 아무것도 설명하지 않은 상태는 단순 문자열이 돼요. 오류 속성은 필요할 때 만들어지므로 절대 nil이 아니고, 객체를 검사하는 대신 IsSuccessful을 확인하면 돼요.

_message의 밑줄은 오타가 아니에요. message는 생성기가 이스케이프하는 68개의 Pascal 예약어 중 하나라서, 그 이름을 가진 스키마 필드는 앞에 밑줄이 붙어 들어와요. type, object, default, index를 비롯한 나머지 목록도 마찬가지이고, 모두 GitHub 스키마 어딘가에 나와요.

생성된 유닛에 들어 있는 것

유닛은 설명을 그대로 반영해요. 따로 선별하지 않기 때문에 GitHub가 문서화한 것은 모두 들어 있고, GitHub가 빠뜨린 것은 들어 있지 않아요.

문서화된 모든 오퍼레이션

메서드 1,225개가 저장소와 콘텐츠, 이슈와 풀 리퀘스트, Actions와 체크 실행, 패키지, 조직과 팀, GitHub Apps, 코드 스캐닝을 비롯한 나머지 영역까지 다뤄요.

메서드마다 응답 클래스 하나

각각 TsgcOpenAPIResponse를 상속하고, 200부터 299까지 true인 IsSuccessful과 함께 ResponseCode, ResponseError를 물려받아요.

3,250개의 모델 클래스

TsgcOpenAPI_repository_Class, TsgcOpenAPI_issue_Class, TsgcOpenAPI_basic_error_Class, TsgcOpenAPI_validation_error_Class를 비롯해 components 섹션의 모든 스키마가 있어요.

태그는 주석으로

GitHub의 태그는 하나뿐인 클라이언트 클래스 안에서 메서드를 묶어 주는 주석으로 나와요. 별도의 클래스가 되지는 않기 때문에 모든 것이 GetOpenAPIClient에 달려 있어요.

사양에 담긴 문서

GitHub 자체 설명이 각 메서드와 속성 위에 Pascal 주석으로 들어오기 때문에, 사용하는 자리에서 IDE가 그대로 보여 줘요.

Enterprise Server도

ghes-3.x 설명도 같은 방식으로 생성돼요. 양쪽과 모두 통신한다면 대상마다 생성된 유닛을 하나씩 두세요.

알아 두면 좋은 네 가지

네 가지 모두 현재 설명으로 실제 생성을 돌려 본 결과예요.

유닛이 아주 커요

약 274,000줄에 12 MB로, 여기서 다루는 공개 사양 가운데 가장 커요. 컴파일은 2초도 걸리지 않지만 그 크기의 파일에서는 IDE 편집기가 느려져요. -x"VERB endpoint" 형식으로 나열한 오퍼레이션을 빼고, 이어서 -p가 남은 오퍼레이션이 쓰지 않는 클래스를 제거해요.

요청 본문은 대부분 문자열이에요

343개의 오퍼레이션이 application/json 본문을 선언하지만, 거의 전부가 이름 있는 스키마 대신 익명 인라인 객체로 설명해요. 인라인 객체는 이름을 붙일 클래스가 없어서 매개변수가 const aBody: string이 되고 JSON은 직접 만들게 돼요. 이름 있는 스키마를 참조하는 소수는 타입이 지정된 클래스를 받아요.

경고 273개, 읽어 볼 가치가 있어요

대부분은 디스크리미네이터 매핑 없는 컴포지션에 관한 것으로, 생성된 클래스가 분기마다 멤버 하나를 갖게 돼요. 일부는 문서가 해석하지 못하는 $ref를 알려 주고, 일부는 성공 상태를 두 개 선언한 오퍼레이션을 알려 주는데 그중 하나만 생성돼요. 생성기는 조용히 고르는 대신 어느 쪽인지 말해 줘요.

요청 한도와 앱 토큰은 직접 다뤄요

생성된 클라이언트는 충실한 HTTP 클라이언트일 뿐 그 이상은 아니에요. ETag 값을 캐시하지도, 403에서 재시도하지도, GitHub App 설치 토큰을 갱신하지도 않아요. ResponseCode를 읽고, OnBeforeRequest로 조건부 요청 헤더를 추가하고, 유닛에 이미 들어 있는 apps 메서드로 설치 토큰을 발급하세요.

블로그에서

OpenAPI Delphi 파서

리더가 실제 사양을 다루는 방식, 그리고 대부분의 경고 뒤에 있는 컴포지션 키워드까지.

게시물 읽기 →

OpenAPI 클라이언트 + 파서

생성된 클라이언트와 그 바탕이 되는 리더를 소개하는 동반 게시물.

게시물 읽기 →

sgcOpenAPI 2026.6

현재 버전의 릴리스 노트예요. 생성기 옵션과 리더 변경 사항이 담겨 있어요.

게시물 읽기 →
최고의 가성비: All-Access모든 eSeGeCe 제품과 프리미엄 지원이 포함되어 연 €1,059부터 이용할 수 있어요.
All-Access 가격 보기

오늘 GitHub 자동화를 구축하세요

sgcOpenAPI는 리더, 코드 생성기, OpenAPI 서버, 그리고 Amazon, Azure, Google, Microsoft용 미리 빌드된 SDK를 함께 제공해요. 하나의 제품, 세 가지 등급이고, 기능이 아니라 좌석 수로 가격이 매겨져요.