GitHub REST API Delphi Client via sgcOpenAPI

GitHub maintains one of the largest OpenAPI descriptions published anywhere, and releases it under the MIT licence. sgcOpenAPI does not ship a hand written GitHub component, it ships a generator. One command line over api.github.com.json produces a single Pascal unit with 1,225 methods, a typed response class for each of them, and a GetOpenAPIClient function that hands you a ready client.

GitHub + sgcOpenAPI

The figures below were measured by running the generator over the current description and compiling the result, not estimated.

Source spec

descriptions/api.github.com/api.github.com.json in github/rest-api-description, declared as OpenAPI 3.0.3. No conversion step is needed.

What comes out

813 paths become 1,225 methods and 1,134 response classes, alongside 3,250 model classes, in one unit of roughly 274,000 lines.

Authentication

Generate with -a 2 and set Authentication.Token.BearerToken at run time. That covers a personal access token and an installation token alike.

It compiles

The generated unit builds clean on RAD Studio 12 for Win32 with nothing on the library path except the sgcOpenAPI Source folder.

Run the generator

GitHub publishes several flavours of the same description. api.github.com.json describes the hosted service and ghes-3.x.json describes GitHub Enterprise Server. Generate from the one you target.

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

File successfully created github.pas

-i takes a local file or a URL and accepts JSON and YAML. -o is the Pascal unit to write, and the unit is named after that file. -a 2 selects token authentication, so every generated method sends Authorization: Bearer. The same executable is a GUI wizard when started with no parameters, and it exits 0 on success, 5 on a bad input file, 6 on a bad output file and 7 when the document cannot be turned into a valid OpenAPI 3 document.

Add the generated .pas to your project and put it in a uses clause. There is no component to install, because sgcOpenAPI registers none and ships no design-time package.

List your repositories

GitHub writes its operation ids with slashes and hyphens, as in repos/list-for-authenticated-user. Those characters cannot appear in a Pascal identifier, so the generator removes them and the method arrives as reposlistforauthenticateduser.

uses
  github;   // the unit you just generated

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;

An endpoint that returns an array gets a response whose Successful is a TsgcOpenAPIArray descendant with a typed Items, here TArray<TsgcOpenAPI_repository_Class>. The base URL comes out of the servers entry, so the generated constructor already sets https://api.github.com. Pagination is not hidden from you: aPer_page and aPage are plain arguments and you loop over pages yourself.

If the lower case names bother you, generate with -m 1 and the methods are named from the operation summary instead, or -m 2 to name them from the endpoint.

Create an issue and list pull requests

Path parameters arrive as leading arguments, in the order the document declares them. The request body arrives as a string, for the reason explained below.

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;

Each response class carries Successful plus one property per status code the document declares, so Error304, Error401, Error403 and Error422 are there to read when the call fails. A status that GitHub describes with a named schema becomes a class, and one it describes with nothing becomes a plain string. The error property is created on demand, so it is never nil and you test IsSuccessful rather than testing the object.

The underscore in _message is not a typo. message is one of the 68 Pascal reserved words the generator escapes, so a schema field with that name arrives with a leading underscore. The same happens to type, object, default, index and the rest of the list, all of which appear somewhere in GitHub's schemas.

What the generated unit contains

The unit mirrors the description. Nothing is curated, so anything GitHub documents is present and anything GitHub leaves out is not.

Every documented operation

1,225 methods, covering repositories and contents, issues and pull requests, Actions and check runs, packages, organisations and teams, GitHub Apps, code scanning and the rest of the surface.

One response class per method

Each one descends from TsgcOpenAPIResponse and inherits IsSuccessful, which is true for 200 to 299, along with ResponseCode and ResponseError.

3,250 model classes

TsgcOpenAPI_repository_Class, TsgcOpenAPI_issue_Class, TsgcOpenAPI_basic_error_Class, TsgcOpenAPI_validation_error_Class and every other schema in the components section.

Tags as comments

GitHub's tags are emitted as comments that group the methods inside the single client class. They do not become separate classes, so everything hangs off GetOpenAPIClient.

The documentation from the spec

GitHub's own descriptions come through as Pascal comments above each method and property, so the IDE shows them where you use them.

Enterprise Server too

The ghes-3.x descriptions generate the same way. Keep one generated unit per target if you talk to both.

Four things worth knowing

All four came out of an actual generation run over the current description.

The unit is very large

About 274,000 lines and 12 MB, the biggest of the public specifications we generate here. It compiles in under two seconds, but the IDE editor is slow with a file that size. -x drops operations you list as "VERB endpoint" and -p then removes the classes no remaining operation uses.

Most request bodies are strings

343 operations declare an application/json body, but almost all of them describe it as an anonymous inline object rather than a named schema. An inline object has no class to name, so the parameter is const aBody: string and you build the JSON. The handful that reference a named schema do get a typed class.

273 warnings, and they are worth reading

Most are about composition without a discriminator mapping, where the generated class carries one member per branch. A few report a $ref the document does not resolve, and a few report an operation that declares two successful statuses, of which only one is generated. The generator says which rather than choosing silently.

Rate limits and app tokens are yours to handle

The generated client is a faithful HTTP client and nothing more. It does not cache ETag values, retry on 403, or refresh a GitHub App installation token. Read ResponseCode, use OnBeforeRequest to add a conditional request header, and mint installation tokens with the apps methods the unit already contains.

From the blog

OpenAPI Delphi parser

How the reader handles real specifications, including the composition keywords behind most of the warnings.

Read post →

OpenAPI client and parser

The companion post that introduces the generated client and the reader it is built on.

Read post →

sgcOpenAPI 2026.6

Release notes for the current version, with the generator options and reader changes.

Read post →
Best value: All-AccessEvery eSeGeCe product, Premium Support included, from €1,059/year.
See All-Access pricing

Build your GitHub automation today

sgcOpenAPI ships the reader, the code generator, the OpenAPI server and pre-built SDKs for Amazon, Azure, Google and Microsoft. One product, three tiers, priced by seat rather than by feature.