sgcOpenAPI 経由の GitHub REST API Delphi クライアント

GitHub は、どこかで公開されている OpenAPI 記述の中でも最大級のものを保守し、MIT ライセンスでリリースしています。sgcOpenAPI は手書きの GitHub コンポーネントを同梱していません。同梱しているのはジェネレーターです。api.github.com.json に対してコマンドラインを 1 回実行すれば、1,225 個のメソッド、そのそれぞれに対応する型付きレスポンスクラス、そしてすぐに使えるクライアントを返す GetOpenAPIClient 関数を備えた、1 つの Pascal ユニットができあがります。

GitHub + sgcOpenAPI

以下の数値は、現在の記述に対してジェネレーターを実行し、その出力をコンパイルして計測したものです。推定値ではありません。

ソース仕様

github/rest-api-description にある descriptions/api.github.com/api.github.com.json。OpenAPI 3.0.3 として宣言されているため、変換ステップは不要です。

出力されるもの

813 個のパスが 1,225 個のメソッドと 1,134 個のレスポンスクラスになり、3,250 個のモデルクラスとともに、約 274,000 行の 1 ユニットに収まります。

認証

-a 2 を付けて生成し、実行時に Authentication.Token.BearerToken を設定します。これでパーソナルアクセストークンもインストールトークンも同じように扱えます。

コンパイルできます

生成されたユニットは、ライブラリパスに sgcOpenAPI の Source フォルダー以外を何も置かない状態で、RAD Studio 12 の Win32 向けにクリーンにビルドされます。

ジェネレーターを実行

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;

配列を返すエンドポイントでは、レスポンスの SuccessfulTsgcOpenAPIArray の子孫になり、型付きの Items を持ちます。ここでは TArray<TsgcOpenAPI_repository_Class> です。ベース URL は servers エントリから取られるため、生成されたコンストラクターはすでに https://api.github.com を設定しています。ページネーションは隠されていません。aPer_pageaPage はただの引数で、ページの繰り返しは自分で書きます。

小文字の名前が気になる場合は -m 1 を付けて生成すると、メソッド名は操作のサマリーから付けられます。-m 2 ならエンドポイントから付けられます。

Issue を作成してプルリクエストを一覧表示

パスパラメーターは、ドキュメントが宣言した順に先頭の引数として渡ってきます。リクエストボディは文字列として渡ってきますが、その理由は下に書いたとおりです。

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 に加えて、ドキュメントが宣言するステータスコードごとに 1 つのプロパティを持ちます。そのため、呼び出しが失敗したときに読めるよう Error304Error401Error403Error422 が用意されています。GitHub が名前付きスキーマで記述したステータスはクラスになり、何も記述していないステータスはただの文字列になります。エラープロパティは必要になった時点で生成されるので nil になることはなく、オブジェクトの有無ではなく IsSuccessful を判定します。

_message のアンダースコアは誤記ではありません。message はジェネレーターがエスケープする 68 個の Pascal 予約語の 1 つなので、その名前を持つスキーマフィールドは先頭にアンダースコアが付いた形で現れます。typeobjectdefaultindex など残りの語も同じで、そのいずれもが GitHub のスキーマのどこかに出てきます。

生成ユニットに含まれるもの

ユニットは記述をそのまま写します。取捨選択は一切行わないので、GitHub が文書化しているものはすべて存在し、GitHub が書いていないものは存在しません。

文書化されたすべての操作

1,225 個のメソッドが、リポジトリとコンテンツ、Issue とプルリクエスト、Actions とチェックラン、Packages、組織とチーム、GitHub Apps、コードスキャン、その他の領域を網羅します。

メソッドごとに 1 つのレスポンスクラス

いずれも TsgcOpenAPIResponse の子孫で、200 から 299 で true になる IsSuccessful と、ResponseCodeResponseError を継承します。

3,250 個のモデルクラス

TsgcOpenAPI_repository_ClassTsgcOpenAPI_issue_ClassTsgcOpenAPI_basic_error_ClassTsgcOpenAPI_validation_error_Class をはじめ、components セクションにあるすべてのスキーマ。

タグはコメントに

GitHub のタグは、単一のクライアントクラスの中でメソッドをグループ分けするコメントとして出力されます。別々のクラスにはならないので、すべては GetOpenAPIClient にぶら下がります。

仕様に書かれたドキュメント

GitHub 自身の説明文は、各メソッドと各プロパティの上に Pascal のコメントとして引き継がれるので、使う場所で IDE が表示してくれます。

Enterprise Server も

ghes-3.x の記述も同じ手順で生成できます。両方と通信するなら、対象ごとに生成ユニットを 1 つずつ用意してください。

知っておきたい 4 点

4 点とも、現在の記述に対する実際の生成実行から得られたものです。

ユニットは非常に大きい

約 274,000 行、12 MB で、ここで扱う公開仕様の中では最大です。コンパイルは 2 秒もかかりませんが、このサイズのファイルでは IDE のエディターが重くなります。-x"VERB endpoint" の形で列挙した操作を除外し、続いて -p が、残った操作のどれからも使われないクラスを取り除きます。

リクエストボディの大半は文字列

343 個の操作が application/json のボディを宣言していますが、そのほとんどは名前付きスキーマではなく無名のインラインオブジェクトとして記述しています。インラインオブジェクトには名前を付けるクラスがないため、パラメーターは const aBody: string となり、JSON は自分で組み立てます。名前付きスキーマを参照している少数の操作では、型付きクラスが得られます。

273 件の警告、読む価値があります

大半は判別子のマッピングがない合成についてで、生成されたクラスは分岐ごとに 1 つのメンバーを持ちます。少数はドキュメントが解決できない $ref の報告で、さらに少数は成功ステータスを 2 つ宣言していて、そのうち 1 つしか生成されない操作の報告です。ジェネレーターは黙って選ぶのではなく、どれなのかを伝えます。

レート制限とアプリトークンは自分で扱う

生成されたクライアントは忠実な HTTP クライアントであり、それ以上のものではありません。ETag の値をキャッシュせず、403 で再試行せず、GitHub App のインストールトークンを更新することもありません。ResponseCode を読み、条件付きリクエストのヘッダーは OnBeforeRequest で追加し、インストールトークンはユニットにすでに含まれている apps のメソッドで発行してください。

ブログから

OpenAPI Delphi パーサー

リーダーが実際の仕様をどう扱うか。警告の大半の背後にある合成キーワードも取り上げます。

投稿を読む →

OpenAPI クライアント + パーサー

生成されたクライアントと、その土台になっているリーダーを紹介する姉妹投稿。

投稿を読む →

sgcOpenAPI 2026.6

現行バージョンのリリースノート。ジェネレーターのオプションとリーダーの変更点を掲載しています。

投稿を読む →
最もお得な選択: All-AccesseSeGeCe の全製品にプレミアムサポートが付いて、年間 €1,059 からご利用いただけます。
All-Access の価格を見る

今日 GitHub 自動化を構築

sgcOpenAPI には、リーダー、コードジェネレーター、OpenAPI サーバー、そして Amazon、Azure、Google、Microsoft 向けのビルド済み SDK が同梱されています。1 製品、3 ティア、機能単位ではなくシート単位の価格です。