GitLab REST API 完整教程 (含示例)

GitLab REST API 完整教程 (含示例)

GitLab 是一个广受欢迎的基于 Web 的 Git 仓库管理器,提供代码托管、问题跟踪、持续集成/持续部署 (CI/CD) 等功能。GitLab 不仅提供了一个友好的用户界面,还提供了一套强大的 REST API,允许开发者通过编程方式与 GitLab 交互,实现自动化任务、集成第三方工具、构建自定义应用等。

本教程将详细介绍 GitLab REST API 的各个方面,包括认证、常用端点、请求格式、响应处理、分页、速率限制等,并提供丰富的代码示例,帮助你快速上手并掌握 GitLab REST API 的使用。

1. 认证

在使用 GitLab REST API 之前,你需要进行身份验证。GitLab 支持多种认证方式,包括:

  • 个人访问令牌 (Personal Access Token, PAT):这是最常用的认证方式。你可以在 GitLab 账户设置中生成一个 PAT,然后在 API 请求中携带这个令牌。PAT 可以设置不同的权限范围 (scopes),以限制其访问权限。
  • OAuth2 令牌:如果你正在开发一个需要访问用户 GitLab 数据的应用程序,可以使用 OAuth2 协议。用户可以通过授权你的应用程序来获取访问令牌。
  • 项目访问令牌 (Project Access Token):类似于 PAT,但作用范围仅限于单个项目。
  • 群组访问令牌 (Group Access Token):类似于 PAT,但作用范围仅限于单个群组。
  • GitLab CI/CD 作业令牌 (CI_JOB_TOKEN):在 CI/CD 作业中,可以使用预定义的 CI_JOB_TOKEN 变量进行认证。

1.1 使用个人访问令牌 (PAT) 认证

  1. 生成 PAT

    • 登录 GitLab。
    • 点击右上角头像,选择 "Edit profile"。
    • 在左侧导航栏中,选择 "Access Tokens"。
    • 输入令牌名称(例如 "My API Token")。
    • 选择所需的 scopes(例如 "api"、"read_repository"、"write_repository" 等)。
    • 点击 "Create personal access token"。
    • 复制生成的令牌(请妥善保管,因为它只显示一次)。
  2. 在 API 请求中使用 PAT

    • 方法一:在请求头中添加 Private-Token

      bash
      curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects"

    • 方法二:在请求头中添加 Authorization: Bearer

      bash
      curl -H "Authorization: Bearer <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects"

      * 方法三:在请求 URL 中添加 private_token 参数 (不推荐,令牌会暴露在日志中):

      bash
      curl "https://gitlab.example.com/api/v4/projects?private_token=<your_personal_access_token>"

1.2 其他认证方式

  • OAuth2 认证流程较为复杂,需要注册应用、获取授权码、交换访问令牌等步骤。请参考 GitLab 官方文档中的 OAuth2 相关章节。
  • 项目/群组访问令牌的生成和使用方式与 PAT 类似,只是作用范围不同。
  • CI_JOB_TOKEN 只能在 CI/CD 作业中使用,无需手动创建。

2. API 端点和版本

GitLab REST API 的端点通常以 /api/v4 开头。v4 是当前主要的 API 版本。

例如,获取所有项目的端点是:

https://gitlab.example.com/api/v4/projects

如果你使用的是 GitLab.com,则将 gitlab.example.com 替换为 gitlab.com

3. 请求方法

GitLab REST API 使用标准的 HTTP 请求方法:

  • GET:获取资源。
  • POST:创建资源。
  • PUT:更新整个资源。
  • PATCH:更新资源的部分属性。
  • DELETE:删除资源。

4. 请求格式

GitLab REST API 支持以下请求格式:

  • 查询参数:对于 GET 请求,可以将参数附加到 URL 中。
  • 请求体:对于 POST、PUT、PATCH 请求,可以将参数放在请求体中。请求体通常使用 JSON 格式。

例如,创建一个新的 issue(使用 JSON 请求体):

bash
curl -H "Private-Token: <your_personal_access_token>" \
-H "Content-Type: application/json" \
-X POST "https://gitlab.example.com/api/v4/projects/<project_id>/issues" \
-d '{
"title": "New Issue Title",
"description": "Issue description here.",
"labels": "bug,enhancement"
}'

5. 响应格式

GitLab REST API 的响应通常使用 JSON 格式。响应包含状态码、响应头和响应体。

  • 状态码

    • 200 OK:请求成功。
    • 201 Created:资源创建成功。
    • 204 No Content:请求成功,但没有返回内容(例如 DELETE 请求)。
    • 400 Bad Request:请求无效。
    • 401 Unauthorized:未认证。
    • 403 Forbidden:无权限访问。
    • 404 Not Found:资源不存在。
    • 409 Conflict:资源冲突。
    • 500 Internal Server Error:服务器错误。
  • 响应头:包含有关响应的元数据,例如 Content-TypeLink(用于分页)等。

  • 响应体:包含请求的资源数据(对于 GET 请求)或操作结果(对于 POST、PUT、PATCH、DELETE 请求)。

6. 常用 API 端点及示例

以下是一些常用的 GitLab REST API 端点及其示例:

6.1 项目 (Projects)

  • 获取所有项目

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects"

  • 获取单个项目

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>"

  • 创建项目

    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -H "Content-Type: application/json" \
    -X POST "https://gitlab.example.com/api/v4/projects" \
    -d '{
    "name": "My New Project",
    "description": "Project description.",
    "visibility": "private"
    }'

  • 搜索项目
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects?search=myproject"

6.2 问题 (Issues)

  • 获取项目的所有问题

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/issues"

  • 获取单个问题

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/issues/<issue_iid>"

  • 创建问题(参见前面的示例)。

  • 更新问题

    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -H "Content-Type: application/json" \
    -X PUT "https://gitlab.example.com/api/v4/projects/<project_id>/issues/<issue_iid>" \
    -d '{
    "title": "Updated issue title",
    "state_event": "close"
    }'

    * 关闭问题:
    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -X PUT "https://gitlab.example.com/api/v4/projects/<project_id>/issues/<issue_iid>?state_event=close"

6.3 合并请求 (Merge Requests)

  • 获取项目的所有合并请求

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/merge_requests"

  • 获取单个合并请求

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/merge_requests/<merge_request_iid>"

  • 创建合并请求

    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -H "Content-Type: application/json" \
    -X POST "https://gitlab.example.com/api/v4/projects/<project_id>/merge_requests" \
    -d '{
    "source_branch": "feature-branch",
    "target_branch": "main",
    "title": "Merge feature branch into main",
    "assignee_id": 123
    }'

    * 接受合并请求
    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -X PUT "https://gitlab.example.com/api/v4/projects/<project_id>/merge_requests/<merge_request_iid>/merge"

6.4 用户 (Users)

  • 获取当前用户信息

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/user"

    * 通过ID获取用户信息:
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/users/<user_id>"

  • 获取所有用户 (需要管理员权限):

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/users"

    * 搜索用户
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/users?search=john"

6.5 分支 (Branches)

  • 列出仓库分支:

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/repository/branches"

    * 获取单个分支:

    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/repository/branches/<branch_name>"

    * 创建分支:
    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -X POST "https://gitlab.example.com/api/v4/projects/<project_id>/repository/branches?branch=<new_branch_name>&ref=<source_branch_or_commit>"

    * 删除分支:
    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -X DELETE "https://gitlab.example.com/api/v4/projects/<project_id>/repository/branches/<branch_name>"

6.6 提交 (Commits)

  • 获取仓库提交列表:
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/repository/commits"

  • 获取单个提交
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/repository/commits/<commit_sha>"

6.7 群组 (Groups)

  • 列出所有群组:
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/groups"

  • 获取单个群组:
    bash
    curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/groups/<group_id>"

  • 创建一个群组 (需要管理员或具有创建群组的权限):

    bash
    curl -H "Private-Token: <your_personal_access_token>" \
    -H "Content-Type: application/json" \
    -X POST "https://gitlab.example.com/api/v4/groups" \
    -d '{
    "name": "My New Group",
    "path": "my-new-group",
    "visibility": "private"
    }'

7. 分页

当 API 返回大量数据时,GitLab 会使用分页来限制每次响应的数据量。你可以通过以下方式控制分页:

  • page 参数:指定要获取的页码。
  • per_page 参数:指定每页返回的数据条数(默认值为 20,最大值为 100)。

例如,获取第 2 页,每页 50 条数据:

bash
curl -H "Private-Token: <your_personal_access_token>" "https://gitlab.example.com/api/v4/projects?page=2&per_page=50"

GitLab 在响应头中提供以下与分页相关的信息:

  • X-Total:总数据条数。
  • X-Total-Pages:总页数。
  • X-Per-Page:每页数据条数。
  • X-Page:当前页码。
  • X-Next-Page:下一页的页码(如果没有下一页,则为空)。
  • X-Prev-Page:上一页的页码(如果没有上一页,则为空)。
  • Link: 包含指向第一页、上一页、下一页和最后一页的链接,方便客户端导航。

8. 速率限制

为了防止滥用,GitLab 对 API 请求进行了速率限制。默认情况下,每个 IP 地址每分钟最多可以发送 600 个请求。

如果达到速率限制,GitLab 会返回 429 Too Many Requests 状态码,并在响应头中包含以下信息:

  • RateLimit-Limit:速率限制的总数。
  • RateLimit-Remaining:当前时间窗口内剩余的请求数。
  • RateLimit-Reset:速率限制重置的时间(Unix 时间戳)。
  • Retry-After:需要等待的秒数(如果提供了)。

建议在你的应用程序中处理速率限制,例如通过捕获 429 错误并等待一段时间后重试。

9. 使用各种编程语言调用GitLab API

以下是一些使用常见编程语言调用 GitLab API 的示例:

9.1 Python

```python
import requests
import os

推荐从环境变量读取,不要直接写在代码里

GITLAB_TOKEN = os.environ.get("GITLAB_TOKEN")
PROJECT_ID = "your_project_id" # 替换为你的项目 ID
BASE_URL = "https://gitlab.example.com/api/v4" # 或 "https://gitlab.com/api/v4"

def get_project_issues(project_id):
url = f"{BASE_URL}/projects/{project_id}/issues"
headers = {"Private-Token": GITLAB_TOKEN}
response = requests.get(url, headers=headers)
response.raise_for_status() # 检查是否有错误
return response.json()

def create_issue(project_id, title, description, labels=None):
url = f"{BASE_URL}/projects/{project_id}/issues"
headers = {
"Private-Token": GITLAB_TOKEN,
"Content-Type": "application/json"
}
data = {
"title": title,
"description": description,
"labels": ",".join(labels) if labels else "" # 将列表转换为逗号分隔的字符串
}
response = requests.post(url, headers=headers, json=data)
response.raise_for_status()
return response.json()

if name == "main":
# 获取所有问题
issues = get_project_issues(PROJECT_ID)
print("Issues:")
for issue in issues:
print(f" - {issue['title']} (ID: {issue['iid']})")

# 创建一个新问题
new_issue = create_issue(PROJECT_ID, "My New Issue", "This is a test issue.", ["bug", "help wanted"])
print(f"\nCreated issue: {new_issue['title']} (ID: {new_issue['iid']})")

```

9.2 JavaScript (Node.js)

```javascript
const axios = require('axios');
require('dotenv').config();

const GITLAB_TOKEN = process.env.GITLAB_TOKEN;
const PROJECT_ID = "your_project_id"; // 替换为你的项目 ID
const BASE_URL = "https://gitlab.example.com/api/v4"; // 或 "https://gitlab.com/api/v4"

async function getProjectIssues(projectId) {
const url = ${BASE_URL}/projects/${projectId}/issues;
const headers = { "Private-Token": GITLAB_TOKEN };
try {
const response = await axios.get(url, { headers });
return response.data;
} catch (error) {
console.error("Error fetching issues:", error.response ? error.response.data : error.message);
throw error;
}
}

async function createIssue(projectId, title, description, labels = []) {
const url = ${BASE_URL}/projects/${projectId}/issues;
const headers = {
"Private-Token": GITLAB_TOKEN,
"Content-Type": "application/json"
};
const data = {
title: title,
description: description,
labels: labels.join(",") // 将数组转换为逗号分隔的字符串
};

try {
    const response = await axios.post(url, data, { headers });
    return response.data;
} catch (error) {
     console.error("Error creating issue:", error.response ? error.response.data : error.message);
     throw error;
}

}

(async () => {
try {
// 获取所有问题
const issues = await getProjectIssues(PROJECT_ID);
console.log("Issues:");
issues.forEach(issue => {
console.log(- ${issue.title} (ID: ${issue.iid}));
});

    // 创建一个新问题
    const newIssue = await createIssue(PROJECT_ID, "My New Issue", "This is a test issue from Node.js.", ["enhancement"]);
    console.log(`\nCreated issue: ${newIssue.title} (ID: ${newIssue.iid})`);

} catch (error) {
  // 错误处理已经在函数内部完成,这里通常不需要额外处理
}

})();
```

9.3 Ruby

```ruby
require 'gitlab'
require 'dotenv/load' # 使用 dotenv 管理环境变量

从环境变量读取,不要直接写在代码里

Gitlab.configure do |config|
config.endpoint = 'https://gitlab.example.com/api/v4' # 或 'https://gitlab.com/api/v4'
config.private_token = ENV['GITLAB_TOKEN']
end

project_id = 'your_project_id' # 替换为你的项目 ID

获取所有问题

issues = Gitlab.issues(project_id)
puts "Issues:"
issues.each do |issue|
puts " - #{issue.title} (ID: #{issue.iid})"
end

创建一个新问题

new_issue = Gitlab.create_issue(project_id, 'My New Issue',
description: 'This is a test issue from Ruby.',
labels: 'bug,documentation' # 标签可以是逗号分隔的字符串或数组
)
puts "\nCreated issue: #{new_issue.title} (ID: #{new_issue.iid})"

关闭一个问题

issue_to_close_iid = new_issue.iid #假设要关闭的就是刚刚创建的问题

Gitlab.close_issue(project_id, issue_to_close_iid)

puts "Issue #{issue_to_close_iid} closed."

获取所有合并请求

merge_requests = Gitlab.merge_requests(project_id)

merge_requests.each do |mr|

puts " - #{mr.title} (ID: #{mr.iid})"

end

```

注意:以上代码示例中:

  • 你需要将 <your_personal_access_token> 替换为你的实际 PAT。
  • 你需要将 <project_id> 替换为你要操作的项目的实际 ID。
  • 你需要将 <issue_iid><merge_request_iid> 替换为实际的问题 ID 和合并请求 ID。
  • 你需要安装相应的库(例如 Python 的 requests,Node.js 的axios, Ruby的gitlab)。
  • 强烈建议将GITLAB_TOKEN 存储在环境变量中,而不是直接写在代码里。 可以使用.env 文件和相应的库(如 Python 的 python-dotenv, Node.js的dotenv, Ruby 的 dotenv)来管理环境变量。

10. 总结

本教程详细介绍了 GitLab REST API 的各个方面,包括认证、常用端点、请求格式、响应处理、分页、速率限制等,并提供了丰富的代码示例。希望这些信息能帮助你快速上手并有效利用 GitLab REST API 来自动化你的工作流程、集成第三方工具或构建自定义应用。

如果你需要更深入地了解某个特定的 API 端点或功能,请参考 GitLab 官方文档:https://docs.gitlab.com/ee/api/。 官方文档提供了最全面、最权威的 API 信息。

THE END