API 与集成
REST、GraphQL、webhook——把 GitHub 与任何外部系统打通
gh 是别人的封装,API 是你自己造工具的原料gh 不够用了
你想做的事,没有现成命令
想做机器人
新开 issue 时自动打标签、有人 star 时发条通知、每天统计贡献图。gh 没有这些功能。
想接外部系统
把 PR 状态同步到飞书群、issue 关闭时更新 Notion 看板。GitHub 和这些工具之间没有现成桥梁。
想自定义查询
「过去一年谁提交最多」「哪些 issue 超过 30 天没动」——网页搜不出来,gh 也不好查。需要原始数据自己算。
这是 gh 背后的真身,也是你造工具的原料。
开始之前
适合谁
- 会基本编程(Python/JS),想自动化 GitHub
- 好奇 gh 背后是怎么工作的
- 想做个小机器人或集成
你将学会
- 用 REST API 查询和操作仓库
- 用 GraphQL 精准取数据
- 理解 token scope 和认证
- 区分 OAuth App 和 GitHub App
- 用 webhook 响应事件
本章暂不覆盖
- GitHub Enterprise API
- 复杂机器人框架(Probot 深度)
- OAuth 完整流程实现
两套 API
GitHub 提供 REST 和 GraphQL 两套接口
| REST API | GraphQL API | |
|---|---|---|
| 风格 | 资源导向 URL | 查询语言,按需取字段 |
| 易学 | 简单直观 | 有学习曲线 |
| 查询效率 | 可能多次请求 | 一次取所需,省请求 |
| 适合 | 简单操作、curl 实测 | 复杂关联查询 |
REST 基础
每个资源有自己的 URL,用 HTTP 方法操作
GET /repos/用户名/仓库名 # 获取仓库信息
POST /repos/用户名/仓库名/issues # 创建 issue
PATCH /repos/用户名/仓库名/issues/12 # 修改 issue 12(改标题/状态等)
GET /repos/用户名/仓库名/issues/12 # 获取单条 issue
closed 来关闭。
基础 URL
https://api.github.com
所有请求以此为前缀。
HTTP 方法对应操作
- GET:读取
- POST:创建
- PATCH/PUT:更新
- DELETE:删除
第一次调用
用 curl 查询公开仓库信息,连认证都不用
$ curl https://api.github.com/repos/octocat/Hello-World
{
"id": 1296269,
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"owner": {
"login": "octocat",
...
},
"stargazers_count": 1000+,
"open_issues_count": 100,
...
}
带认证的调用
用 PAT 认证后,能读私有仓库、能写操作
# 带 token 的请求(注意 Authorization 头)
$ curl -H "Authorization: Bearer 你的TOKEN" \
https://api.github.com/user
# 查看当前认证用户信息
{
"login": "你的用户名",
"name": "...",
"public_repos": 10,
...
}
认证方式
Authorization: Bearer TOKEN(推荐)- URL 参数
?access_token=TOKEN(已废弃,不安全) - 建议用环境变量存 token,别写死
$GITHUB_TOKEN 环境变量,curl 里写 -H "Authorization: Bearer $GITHUB_TOKEN"。
用 API 创建 issue
POST 请求带 JSON body——能写就能自动化
$ curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/你/仓库/issues \
-d '{"title":"通过 API 创建","body":"测试","labels":["bug"]}'
# 返回创建好的 issue(含编号、URL 等)
直接调 API 更灵活——你可以批量创建、从外部数据源导入、和别的系统联动。
速率限制
API 有调用频率上限,防止滥用
| 认证状态 | 每小时限制 |
|---|---|
| 未认证 | 60 次 |
| 带 token(普通用户) | 5000 次 |
| GitHub App | 更高(按安装算) |
查看剩余额度
$ curl -H "Authorization: Bearer $TOKEN" \
https://api.github.com/rate_limit
返回 remaining / reset 等字段。
脚本里记得处理 403(超限)——sleep 等 reset 时间再重试。
分页
返回多的接口会分页,默认一页 30 条
# 指定每页数量和页码
$ curl -H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/你/仓库/issues?per_page=100&page=1"
# Link 响应头告诉你有没有下一页
Link: <...&page=2>; rel="next", <...&page=5>; rel="last"
GraphQL 登场
用一条查询精确取你想要的字段——不过度、不不足
$ curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"{ viewer { login bio repositories(privacy: PUBLIC) { totalCount } } }"}' \
https://api.github.com/graphql
{
"data": {
"viewer": {
"login": "你的用户名",
"bio": "...",
"repositories": {
"totalCount": 10
}
}
}
}
更大的优势是关联数据一次取:「我的前 10 个仓库的最近 5 个 PR」——REST 要 N+1 次请求,GraphQL 一次搞定。
GraphQL 实战
一次查询取多层数据——REST 要发很多请求
query {
viewer {
login
repositories(first: 5, orderBy: {field: UPDATED_AT}) {
nodes {
name
issues(states: [OPEN], first: 3) {
totalCount
nodes { number title }
}
}
}
}
}
这条查询做了什么
取当前用户 → 最近更新的 5 个仓库 → 每个仓库前 3 个 open issue(含编号标题)和 issue 总数。
用 REST 至少 6 次请求,GraphQL 一次返回。
适合仪表盘、统计页面这类需要聚合数据的场景。
GraphiQL 探索器
可视化写 GraphQL 的官方工具——带自动补全
在哪
docs.github.com/graphql → 点「GitHub GraphQL Explorer」→ 用 GitHub 登录。
能做什么
- 左侧写查询,右侧实时看结果
- 有字段自动补全和文档
- 报错提示明确(哪个字段拼错)
- 写好后复制到代码里
token 权限
scope 决定你的 token 能调哪些 API
| scope | 能做什么 |
|---|---|
| (无 scope) | 读公开数据、读自己信息 |
repo |
读写仓库(公开+私有) |
read:user |
读用户资料 |
user:email |
读邮箱 |
workflow |
改 GitHub Actions workflow |
调 API 报 403 时,先检查 token 有没有对应 scope。第 10 章讲过的最小权限原则这里同样适用。
两种 App
OAuth App 和 GitHub App——给第三方做集成时的身份
| OAuth App | GitHub App | |
|---|---|---|
| 权限粒度 | 用户级(拿用户全部权限) | 细粒度(按仓库、按操作) |
| 认证对象 | 代表用户 | 独立身份 |
| webhook | 需手动配 | 原生支持 |
| 适合 | 简单工具 | 正式集成、机器人 |
octokit SDK
GitHub 官方多语言 SDK,不用手写 HTTP
// JavaScript: @octokit/rest
import { Octokit } from "@octokit/rest";
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
// 列出你的仓库
const { data } = await octokit.rest.repos.listForAuthenticatedUser();
console.log(data.map(r => r.full_name));
// 创建 issue
await octokit.rest.issues.create({
owner: '你', repo: '项目',
title: '通过 SDK 创建',
});
各语言 SDK
- JS/TS:
@octokit/rest、@octokit/graphql - Python:
PyGithub(社区)、githubkit - Go:
google/go-github
Python 实战
用 PyGithub 统计仓库贡献者
from github import Github
import os
g = Github(os.environ["GITHUB_TOKEN"])
repo = g.get_repo("你/项目")
# 统计每个贡献者的 commit 数
contributors = repo.get_contributors()
for c in contributors[:5]:
print(f"{c.login}: {c.contributions} 次提交")
# 列出超过 30 天没动的 issue
import datetime
since = datetime.datetime.now() - datetime.timedelta(days=30)
old_issues = [i for i in repo.get_issues(state="open")
if i.updated_at < since]
print(f"有 {len(old_issues)} 个 issue 超过 30 天没更新")
跑一遍发现没动过的 issue,是开源项目维护的常见脚本。
webhook
GitHub 主动 POST 通知你「发生了事件」——反向 API

图:webhook 工作原理
【AI 生图提示词】请生成一张中文技术示意图,风格简洁、配色柔和、适合教学: - 画面主体:左侧 GitHub 云朵图标,右侧「你的服务器」图标,中间一个 webhook 配置框 - 各元素关系:GitHub 上发生事件(如新 issue),GitHub 向你配置的 URL 发 HTTP POST 请求,你的服务器接收并处理 - 关键标注:GitHub 侧标「事件触发(push/issue/PR)」,箭头标「POST payload」,你的服务器标「接收后执行逻辑(打标签/通知)」 - 配色建议:浅灰背景,GitHub 用深蓝,你的服务器用绿色,箭头橙色 - 画面比例:16:9 - 避免:3D 效果、过多文字
配置 webhook
告诉 GitHub「发生 X 事件时,POST 到这个 URL」
在哪配
仓库 → Settings → Webhooks → Add webhook。
关键设置
- Payload URL:你的服务器接收地址
- Content type:选 application/json
- Secret:用于验证请求确实来自 GitHub
- Events:勾选要监听的事件(push、issues、pull_request 等)
webhook 负载
GitHub POST 过来的 JSON——含事件全部信息
// issues 事件的 payload(节选)
{
"action": "opened",
"issue": {
"number": 42,
"title": "登录失灵",
"body": "点击登录没反应...",
"user": { "login": "reporter" },
"labels": []
},
"repository": {
"full_name": "你/项目"
}
}
怎么用
服务器收到后,根据 action 和内容做处理:
- 新 issue 标题含「bug」→ 自动加 bug label
- 新 PR → 发飞书通知
- push 到 main → 触发部署
实战:自动打标签
新 issue 根据标题自动分类——webhook + API 组合
# Flask 接收 webhook
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def webhook():
data = request.json
if data["action"] == "opened":
title = data["issue"]["title"].lower()
labels = []
if "bug" in title or "失灵" in title:
labels.append("bug")
if "文档" in title or "doc" in title:
labels.append("documentation")
if labels:
repo = data["repository"]["full_name"]
num = data["issue"]["number"]
# 调 API 加 label
add_labels(repo, num, labels)
return "", 200
三种自动化
什么时候用 Actions、webhook、外部脚本调 API
| 方案 | 适合 | 举例 |
|---|---|---|
| GitHub Actions | 仓库内的、事件触发的 | push 时测试、定时检查 |
| webhook + 自建服务 | 跨系统集成、实时 | 同步到飞书、通知 IM |
| 脚本调 API | 一次性、批处理 | 统计贡献、批量改 label |
很多场景三者都能做。优先级:能用 Actions 就用 Actions(免服务器),要跨系统才上 webhook。
Probot 框架
基于 Node.js 的 GitHub App 框架——少写样板代码
它封装了什么
- webhook 接收和签名验证
- GitHub App 认证(自动拿 token)
- API 调用(octokit 集成)
- 常用模板(欢迎新贡献者、自动关闭陈旧 PR)
适合
想正经做一个机器人/集成。比起自己从零写 webhook 服务,Probot 省去重复劳动。
现成应用市场:probot.github.io/apps。
动手试一试
用 API 写一个自己的小工具
你的任务
任务:用 API 做一个能查询并展示你仓库数据的脚本。
要求(任选一个):
- 统计你所有仓库的 star 总数和按语言分布
- 列出某个仓库最近 10 个 open issue 的标题
- 用 GraphQL 一次查出你最近 5 个仓库的 PR 数量
通用要求:
- token 从环境变量读,不写死
- 处理分页(如果需要)
- 输出格式化的结果
提示
- 先用 curl 在命令行验证查询对不对,再写代码
- 遇到 403 检查 token scope 或是否超限
小结
你已经能读写 GitHub 的任意数据,并让它主动通知你
本章要点
- REST API 简单直观,GraphQL 高效精准
- PAT 认证 + scope 控制权限
- GitHub App(细粒度)优于 OAuth App(粗粒度)
- webhook 让 GitHub 主动通知,适合实时集成
- octokit SDK 各语言都有,省去手写 HTTP