Bash và REST API: Gọi và xử lý API hiệu quả trong DevOps
Hướng dẫn gọi REST API với curl trong Bash: GET/POST/PUT/DELETE, parse JSON với jq, bearer auth, retry logic, và tự động hóa GitHub/Slack API trong DevOps.
Trong bài viết trước, chúng ta đã tìm hiểu cách tối ưu hiệu suất với Parallel Execution. Bây giờ, chúng ta sẽ kết hợp Bash với REST API — cầu nối để giao tiếp với hầu hết mọi dịch vụ hiện đại: từ GitHub, Slack, Jira, đến monitoring dashboard và CI/CD platform.
Trong DevOps, API là cách để lấy dữ liệu, kiểm tra trạng thái, hay điều khiển hệ thống từ xa. Và Bash là công cụ hoàn hảo để gọi API — curl có sẵn trên mọi server, jq parse JSON cực nhanh, và bạn có thể tích hợp vào bất kỳ script nào mà không cần cài thêm thư viện hay framework.
Bài viết này sẽ hướng dẫn bạn cách gọi API với curl, parse JSON response với jq, xử lý authentication, retry logic, và một script thực hành tự động tạo GitHub Issue khi deploy thất bại.
Gọi API với curl
Các method cơ bản
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# GET — lấy dữ liệucurl -s "https://api.example.com/status"# POST — tạo dữ liệu mớicurl -s -X POST \
-H "Content-Type: application/json"\
-d '{"title": "Bug report", "body": "Something went wrong"}'\
"https://api.example.com/issues"# PUT — cập nhật dữ liệucurl -s -X PUT \
-H "Content-Type: application/json"\
-d '{"status": "resolved"}'\
"https://api.example.com/issues/42"# DELETE — xóa dữ liệucurl -s -X DELETE "https://api.example.com/issues/42"
# Ví dụ: Kiểm tra API health với timeout và retryHTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}"\
--connect-timeout 5 --retry 3 --retry-delay 2\
"https://api.example.com/health")if[["$HTTP_CODE" -eq 200]];thenecho"API is healthy"elseecho"API returned status $HTTP_CODE"fi
Parse JSON với jq
jq là công cụ line-oriented processor cho JSON — cực kỳ mạnh mẽ khi kết hợp với curl.
#!/usr/bin/env bash
# ==============================================================================# Script : github-issue-on-failure.sh# Mục đích: Tự động tạo GitHub Issue khi pipeline deploy thất bại# ==============================================================================set -euo pipefail
# Cấu hìnhreadonlyGITHUB_TOKEN="${GITHUB_TOKEN:?GITHUB_TOKEN is required}"readonlyGITHUB_REPO="${GITHUB_REPO:?GITHUB_REPO is required (owner/repo)}"readonlyAPI_BASE="https://api.github.com/repos/${GITHUB_REPO}"readonlySLACK_WEBHOOK="${SLACK_WEBHOOK:-}"# Thông tin pipeline (từ CI/CD environment)readonlyPIPELINE_URL="${CI_PIPELINE_URL:-${BUILD_URL:-unknown}}"readonlyCOMMIT_SHA="${CI_COMMIT_SHA:-$(git rev-parse --short HEAD 2>/dev/null ||echo'unknown')}"readonlyCOMMIT_MSG="${CI_COMMIT_MESSAGE:-$(git log -1 --pretty=%B 2>/dev/null ||echo'unknown')}"readonlyDEPLOY_ENV="${DEPLOY_ENV:-production}"readonlyTIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')# HeadersAUTH_HEADER="Authorization: Bearer ${GITHUB_TOKEN}"ACCEPT_HEADER="Accept: application/vnd.github.v3+json"# Hàm gọi GitHub APIgithub_api(){localmethod="$1"localendpoint="$2"localdata="${3:-}"localargs=( -s -f -S
-X "$method" -H "$AUTH_HEADER" -H "$ACCEPT_HEADER" -H "Content-Type: application/json")if[[ -n "$data"]];thenargs+=(-d "$data")fi curl "${args[@]}""${API_BASE}${endpoint}"}# Kiểm tra issue đã tồn tại chưa (tránh duplicate)check_duplicate(){localtitle="$1"local existing
existing=$(github_api GET "/issues?state=open&labels=auto-deploy-failure&per_page=100" 2>/dev/null ||echo"[]")echo"$existing"| jq -r '.[].title'| grep -qF "$title"}# Tạo GitHub Issuecreate_issue(){localtitle="$1"localbody="$2"if check_duplicate "$title";thenecho"[INFO] Duplicate issue found, skipping creation"return0filocal payload
payload=$(jq -n \
--arg title "$title"\
--arg body "$body"\
'{
title: $title,
body: $body,
labels: ["auto-deploy-failure", "ops"],
assignees: []
}')local response
response=$(github_api POST "/issues""$payload")if[[$? -eq 0]];thenlocal issue_url
issue_url=$(echo"$response"| jq -r '.html_url')local issue_number
issue_number=$(echo"$response"| jq -r '.number')echo"[INFO] Created issue #${issue_number}: ${issue_url}"elseecho"[ERROR] Failed to create issue" >&2return1fi}# Gửi Slack notificationnotify_slack(){localmessage="$1"if[[ -n "$SLACK_WEBHOOK"]];then curl -s -X POST -H 'Content-type: application/json'\
--data "{\"text\":\"${message}\"}""$SLACK_WEBHOOK" >/dev/null 2>&1fi}# Mainmain(){localfail_reason="${1:-Unknown failure}"localissue_title="[DEPLOY FAIL] ${DEPLOY_ENV} — ${COMMIT_SHA} — $(date '+%Y-%m-%d')"localissue_body="## Deploy Failure Report
**Environment:** \`${DEPLOY_ENV}\`
**Commit:** \`${COMMIT_SHA}\`
**Time:** ${TIMESTAMP}**Pipeline:** ${PIPELINE_URL}### Commit Message
\`\`\`
${COMMIT_MSG}\`\`\`
### Failure Reason
${fail_reason}### Required Actions
- [ ] Check pipeline logs
- [ ] Verify deployment artifacts
- [ ] Confirm service health
- [ ] Update issue when resolved
---
*Auto-generated by deployment monitoring script*"echo"Creating GitHub issue for failed deploy..." create_issue "$issue_title""$issue_body"localslack_msg="*[DEPLOY FAILURE]* ${DEPLOY_ENV}\nCommit: \`${COMMIT_SHA}\`\nReason: ${fail_reason}\nPipeline: ${PIPELINE_URL}" notify_slack -e "$slack_msg"}main "$@"
Sử dụng trong pipeline
1
2
3
4
5
6
7
8
9
# GitHub Actions exampledeploy:script:- bash deploy.shafter_script:- | if [[ "$CI_JOB_STATUS" == "failed" ]]; then
bash .github/scripts/github-issue-on-failure.sh "Deploy job failed"
fi
Kết quả mẫu
1
2
Creating GitHub issue for failed deploy...
[INFO] Created issue #247: https://github.com/org/repo/issues/247
GitHub Issue được tạo với:
Title: [DEPLOY FAIL] production — a1b2c3d — 2026-09-03
Labels: auto-deploy-failure, ops
Body chứa environment, commit info, pipeline URL và checklist
Ghi chú triển khai
Token security: Luôn lưu GITHUB_TOKEN dưới dạng secret variable, không hardcode trong script. GitHub token cần scope repo để tạo issue.
Duplicate prevention: Script kiểm tra issue trùng lặp trước khi tạo — tránh spam khi pipeline fail nhiều lần liên tiếp.
jq dependency: Đảm bảo jq đã cài trên runner/CI machine. Hầu hết CI image đều có sẵn, nhưng nếu không, thêm apt-get install -y jq vào pipeline.
Rate limiting: GitHub API có rate limit (5000 requests/hour cho authenticated user). Script này gọi ít request nên không vấn đề, nhưng khi viết script gọi API yoğun, hãy check header X-RateLimit-Remaining.
Multi-platform: Script trên dùng GitHub API, nhưng bạn có thể thay thế endpoint để tạo issue trên GitLab, Jira, hay bất kỳ hệ thống issue tracking nào có REST API.
Lời kết
Bash và REST API là combination cực kỳ mạnh mẽ trong DevOps. Từ việc gọi API đơn giản với curl, parse JSON phức tạp với jq, xử lý retry logic, đến tự động tạo GitHub Issue khi deploy thất bại — tất cả đều có thể thực hiện chỉ với Bash mà không cần framework nặng.
Ở bài tiếp theo, chúng ta sẽ khám phá Bash và Cloud CLI: cách quản lý AWS, GCP, Azure từ Bash, query JSON output, và tự động hóa cloud tasks.