| 1 | --- |
| 2 | title: GitHub API compatibility |
| 3 | description: Point the gh CLI and Octokit at your host with the /api/v3 facade. |
| 4 | --- |
| 5 | |
| 6 | The host exposes a GitHub REST v3 facade at `/api/v3`, so tooling that |
| 7 | already speaks GitHub works against it unchanged. It is a translation |
| 8 | layer over the same operations as `/api/v1`, reshaped into GitHub's |
| 9 | requests and responses. |
| 10 | |
| 11 | ## Using `gh` |
| 12 | |
| 13 | `gh` reaches other hosts through its Enterprise settings and sends |
| 14 | REST to `https://<host>/api/v3/...`: |
| 15 | |
| 16 | ```sh |
| 17 | export GH_HOST="git.example.com" |
| 18 | export GH_ENTERPRISE_TOKEN="YOUR_CREDENTIAL" |
| 19 | |
| 20 | gh api "repos/acme/web" |
| 21 | gh api "repos/acme/web/commits" |
| 22 | gh api "repos/acme/web/pulls" --paginate |
| 23 | ``` |
| 24 | |
| 25 | The host must be reachable over HTTPS. `gh` refuses plaintext for |
| 26 | enterprise hosts. |
| 27 | |
| 28 | ## Using Octokit |
| 29 | |
| 30 | ```typescript |
| 31 | import { Octokit } from "octokit"; |
| 32 | |
| 33 | const octokit = new Octokit({ |
| 34 | baseUrl: `https://${host}/api/v3`, |
| 35 | auth: process.env.GIT_TOKEN, |
| 36 | }); |
| 37 | |
| 38 | await octokit.rest.repos.get({ owner: "acme", repo: "web" }); |
| 39 | ``` |
| 40 | |
| 41 | ## Covered |
| 42 | |
| 43 | Repository metadata, branches, commits and commit detail, comparison, |
| 44 | file contents, the authenticated-user probe at `/user`, and pull |
| 45 | requests: list, create, get, update, merge, and changed files. |
| 46 | |
| 47 | `gh` and Octokit send `Authorization: token <t>`, so the middleware in |
| 48 | front of the facade should accept that scheme alongside Basic. The |
| 49 | credential is whatever your middleware verifies. `/user` is the probe |
| 50 | `gh` makes; the engine has no user to answer with, so override `user` when |
| 51 | registering the `github` group with `HttpApiBuilder.group`. Spread |
| 52 | `git.github` into `handleAll` and supply your own `user` handler. |
| 53 | [HTTP routes](/git/blocks/server#replace-a-git-handler) shows how to replace |
| 54 | a handler using your application session. |
| 55 | |
| 56 | Pagination uses `Link` headers with `rel="next"`. The next URL carries |
| 57 | an opaque cursor, which `gh api --paginate` and Octokit's paginator |
| 58 | follow as-is. |
| 59 | |
| 60 | ## Shape mappings |
| 61 | |
| 62 | - A merged pull request is `state: "closed"` with `merged: true`. |
| 63 | - Ids are integers derived from the internal identifiers. |
| 64 | - Errors are `{ message }` with GitHub's status conventions: `401` |
| 65 | "Requires authentication", `404` "Not Found", `405` for an |
| 66 | unsupported merge method, `409` for a conflict. |
| 67 | |
| 68 | ## Not covered |
| 69 | |
| 70 | **GraphQL.** `gh`'s porcelain, `gh pr create`, `gh pr list`, |
| 71 | `gh issue`, speaks GraphQL and does not work. Use `gh api` with REST |
| 72 | paths. |
| 73 | |
| 74 | Also absent: issues, reviews, comments, checks, search, rename |
| 75 | detection in file lists, and per-file line counts. Additions and |
| 76 | deletions report zero, since the host does not compute content diffs. |
| 77 | Fetch the blobs and diff client-side. |