Um momento
0xC0Lesson 13 of 14

The gh CLI and the GitHub API

Drive GitHub from the terminal with gh, and automate it with the REST and GraphQL APIs, pagination, rate limits and webhooks.

26 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • Use the gh CLI for pull requests, issues, runs and releases
  • Call the REST API with authentication, and handle pagination and rate limits
  • Choose between REST, GraphQL and webhooks for an automation

Everything you’ve clicked in this track can be done from the terminal with gh, GitHub’s official CLI - and scripted through the API. Maintainers who live in the terminal save hours a week.

a day in the terminal
1gh auth login                              # sign in once (stores a token securely)
2gh repo clone dungeon-dash/dungeon-dash
3gh issue list --label "good first issue"
4gh issue create --title "Boss music too loud" --label bug
5gh pr checkout 128                         # check out someone's PR locally to test it
6gh pr review 128 --approve --body "Played it - the dragon is great!"
7gh pr checks 128                           # CI status
8gh run watch                               # follow a running workflow live
9gh run rerun --failed                      # re-run failed jobs
10gh api repos/dungeon-dash/dungeon-dash/releases/latest --jq .tag_name

The REST API

The REST API lives at https://api.github.com. Each resource has a URL - /repos/OWNER/REPO/issues, /repos/OWNER/REPO/pulls/128, /users/mira - and returns JSON. Authenticate with a token in a header (Authorization: Bearer TOKEN); gh api does that for you.

Two things every API script must handle:

  • Pagination. Lists come in pages (30 items by default, up to 100 with per_page=100). The Link response header gives the URLs of the next and last pages - follow next until there isn’t one. (gh api --paginate does it automatically.)
  • Rate limits. Authenticated requests get 5,000 per hour (unauthenticated: 60). The x-ratelimit-remaining and x-ratelimit-reset headers tell you where you stand - back off when you get close.
pagination.py
1import re
2
3link_header = (
4    '<https://api.github.com/repos/dungeon-dash/dungeon-dash/issues?page=2>; rel="next", '
5    '<https://api.github.com/repos/dungeon-dash/dungeon-dash/issues?page=14>; rel="last"'
6)
7links = {rel: url for url, rel in re.findall(r'<([^>]+)>;\s*rel="(\w+)"', link_header)}
8print("next:", links["next"])
9print("pages:", re.search(r"[?&]page=(\d+)", links["last"]).group(1))
Output
next: https://api.github.com/repos/dungeon-dash/dungeon-dash/issues?page=2
pages: 14

GraphQL and webhooks

  • The GraphQL API (https://api.github.com/graphql) lets one request ask for exactly the fields you need across related objects - “the last 10 PRs with their reviews and check results” - instead of many REST calls.
  • Webhooks flip the direction: instead of asking GitHub over and over (“any new issues yet?”), GitHub sends an HTTP POST to your server when something happens - an issue opened, a PR merged, a release published. Verify each delivery’s signature header with your webhook secret.
  • For automation that should live inside the repository, a GitHub Actions workflow listening for the same events is usually simplest; for a service acting across many repositories, build a GitHub App with fine-grained permissions.

Try it

Which tool for the job?

Pick the best fit for each automation.

0 of 6 sortedScore 0/0
  • “Check out PR #128 locally to try it”

  • “Every Monday, export all open issues from 40 repositories to a spreadsheet”

  • “Post to the team chat the moment a release is published”

  • “See whether your PR’s checks passed, from the terminal”

  • “Fetch 50 PRs with their reviews and labels in one request”

  • “Label every new issue that mentions “crash””

Key takeaways

  • gh does pull requests, issues, runs, releases and raw API calls from the terminal.

  • The REST API returns JSON per resource; authenticate with a token in the Authorization header.

  • Follow the Link header for pagination and watch the rate-limit headers.

  • GraphQL fetches nested data in one request; webhooks and Actions react to events instead of polling.

Lesson quiz

7 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: automate GitHub chores with Python

Real GitHub work involves lots of small automation: matching CODEOWNERS, expanding build matrices, bumping versions, reading the API. Write those helpers in Python and run them against sample inputs - locally in your browser, with no GitHub account needed.

Exercise 1

Follow the pages

+25 XP

Simulate a paginated API. The input is a series of pages, each a Link: header line followed by a JSON array of issues on the next line. Starting with the first page, follow rel="next" links, matching each URL’s page=N to the N-th page in the input (pages are numbered from 1) until there’s no next link. Collect the issues’ numbers.

Print fetched N pages, M issues, then the numbers of the open issues ("state": "open") sorted, as open: 3 7 12. A page whose Link header is empty has no next page.

  • Three pages
  • One page
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Stay under the rate limit

+25 XP

Your script must make a number of API calls. The input is calls_needed remaining limit reset_in_minutes - how many calls you need, how many you have left in the current window, the per-hour limit, and when the window resets. Print now: N calls, then how many calls go into each later hourly window (after 25 min: 5000 calls, then after 85 min: ..., adding 60 minutes each time) until all are done, then total wait: X min (the start of the last window used, or 0 if everything fits now).

  • Big export
  • Fits now
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: