Chuyển tới nội dung chính

\{/* Trang này được tạo tự động từ SKILL.md của kỹ năng bởi website/scripts/generate-skill-docs.py. Chỉnh sửa nguồn SKILL.md, không phải trang này. */}

Gỡ lỗi Graphql còn lại

Gỡ lỗi API REST/GraphQL: mã trạng thái, xác thực, lược đồ, repro.

Siêu dữ liệu kỹ năng

NguồnTùy chọn — cài đặt với
`Hermes skills install official/software-development/rest-graphql-debug
`
Đường dẫn

optional-skills/software-development/rest-graphql-debug ` | | Phiên bản |

1.2.0 ` | | Tác giả | eren-karakus0 | | Giấy phép | MIT | | Thẻ |

API

, `rest

, `graphql

, `http

, `debugging

, `testing

, `curl

, integration | | Kỹ năng liên quan | XPROTECTX35XPROTECTX, XPROTECTX36XPROTECTX |

Tham khảo: đầy đủ SKILL.md

thông tin

Sau đây là định nghĩa kỹ năng đầy đủ mà Hermes tải khi kỹ năng này được kích hoạt. Đây là những gì tác nhân coi là hướng dẫn khi kỹ năng được kích hoạt.

Kiểm tra và gỡ lỗi API

Thúc đẩy chẩn đoán REST và GraphQL thông qua các công cụ Hermes — terminal dành cho `curl

, execute_code dành cho Python `requests

, web_extract dành cho tài liệu của nhà cung cấp. Cô lập lớp bị lỗi trước khi đoán cách khắc phục.

Khi nào nên sử dụng

  • API trả về trạng thái hoặc nội dung không mong muốn
  • Xác thực không thành công (401/403 sau khi làm mới mã thông báo, OAuth, khóa API)
  • Hoạt động trong Postman nhưng bị lỗi về mã
  • Gỡ lỗi tích hợp Webhook/gọi lại
  • Xây dựng hoặc xem xét các thử nghiệm tích hợp API
  • Vấn đề giới hạn tỷ lệ hoặc phân trang

Bỏ qua phần hiển thị giao diện người dùng, điều chỉnh truy vấn DB hoặc cơ sở hạ tầng DNS/tường lửa (tăng cấp).

Nguyên tắc cốt lõi`Cô lập lớp, sau đó sửa. 200 OK có thể ẩn dữ liệu bị hỏng. Số 500 có thể che dấu lỗi đánh máy xác thực một ký tự. Đi theo chuỗi theo thứ tự; không bao giờ bỏ qua một bước.

`

  1. Connectivity → can we reach the host at all? 1.5 Timeouts → connect-slow vs read-slow?
  2. TLS/SSL → cert valid and tRusted?
  3. Auth → credentials correct and unexpired?
  4. Request format → payload shape match server expectations?
  5. Response parse → does our code accept what came back?
  6. Semantics → does the data mean what we assume?

`

Khởi động nhanh 5 phút

REST qua terminal


# Verbose request/response exchange
terminal('curl -v https://API.example.com/users/1')

# POST with JSON
terminal("""curl -X POST https://API.example.com/users \\
-H 'Content-Type: application/JSON' \\
-H "Authorization: Bearer $TOKEN" \\
-d '\\\{"name":"test","email":"test@example.com"}'""")

# Headers only
terminal('curl -sI https://API.example.com/health')

# Pretty-print JSON
terminal('curl -s https://API.example.com/users | Python3 -m JSON.tool')

`

### GraphQL qua terminal

``` python
terminal("""curl -X POST https://API.example.com/graphql \\

-H 'Content-Type: application/JSON' \\
-H "Authorization: Bearer $TOKEN" \\
-d '\\\{"query":"\\{ user(id: 1) \\{ name email } }"}'""")

`
``**GraphQL gotcha:** máy chủ thường trả về HTTP 200 ngay cả khi truy vấn không thành công. Luôn kiểm tra trường
`errors
` bất kể mã trạng thái:

``` python
execute_code('''
import os, requests
resp = requests.post(
"https://API.example.com/graphql",
JSON=\\\{"query": "\\{ user(id: 1) \\{ name email } }"},
headers=\\\{"Authorization": f"Bearer \\\{os.environ['TOKEN']}"},
timeout=10,
)
data = resp.JSON()
if data.get("errors"):
for err in data["errors"]:
print(f"GraphQL error: \\\{err['message']} (path: \\\{err.get('path')})")
print(data.get("data"))
''')

`

### Python (yêu cầu) thông qua exec_code

`Python
execute_code('''
import requests
resp = requests.get(
"https://API.example.com/users/1",
headers=\\\{"Authorization": "Bearer <TOKEN>"},
timeout=(3.05, 30), # (connect, read)
)
print(resp.status_code, dict(resp.headers))
print(resp.text[:500])
''')

`

## Luồng gỡ lỗi theo lớp

### Bước 1 — Kết nối

`Python
terminal('nslookup API.example.com')
terminal('curl -v --connect-timeout 5 https://API.example.com/health')

`
``Lỗi: DNS không phân giải được, tường lửa, yêu cầu VPN, thiếu proxy.

### Bước 1.5 - Hết giờ

Phân biệt *không thể với tới* với *đạt được nhưng chậm*:

`Python
terminal('''curl -w "dns:%\\\{time_namelookup}s connect:%\\\{time_connect}s TLS:%\\\{time_appconnect}s ttfb:%\\\{time_starttransfer}s total:%\\\{time_total}s\\n" \\

-o /dev/null -s https://API.example.com/endpoint''')

`
``Trong Python, luôn vượt qua thời gian chờ của bộ dữ liệu -
`requests
` không có mặc định và sẽ bị treo vĩnh viễn:

``` python
execute_code('''
import requests
from requests.exceptions import ConnectTimeout, ReadTimeout
try:
requests.get(url, timeout=(3.05, 30))
except ConnectTimeout:
print("Cannot reach host — DNS, firewall, VPN")
except ReadTimeout:
print("Connected but server is slow")
''')

`
``Chẩn đoán:
`time_connect
` cao là mạng/tường lửa;
`time_starttransfer
` cao với
`time_connect
` thấp là máy chủ chậm.

### Bước 2 — TLS/SSL

`Python
terminal('curl -vI https://API.example.com 2>&1 | grep -E "SSL|subject|expire|issuer"')

`
``Lỗi: chứng chỉ hết hạn, tự ký, tên máy chủ không khớp, thiếu gói CA. Chỉ sử dụng

`
-k
` để gỡ lỗi đặc biệt, không bao giờ dùng trong mã.

### Bước 3 - Xác thực

``` python

# Token validity check
terminal('curl -s -o /dev/null -w "%\\\{http_code}\\n" -H "Authorization: Bearer $TOKEN" https://API.example.com/me')

# Decode JWT exp claim — handles base64url padding correctly
execute_code('''
import JSON, base64, os
tok = os.environ["TOKEN"]
payload = tok.split(".")[1]
payload += "=" * (-len(payload) % 4)
print(JSON.dumps(JSON.loads(base64.urlsafe_b64decode(payload)), indent=2))
''')

`
``Danh sách kiểm tra:
- Mã thông báo đã hết hạn? (Yêu cầu
`exp
` trong JWT)
- Kế hoạch đúng không? Bearer vs Basic vs Token vs
`X-API-Key

- Môi trường phù hợp? Phím dàn dựng trên sản phẩm là một phím cổ điển
- Khóa API trong tiêu đề so với thông số truy vấn (

?API_key=

)?

### Bước 4 - Định dạng yêu cầu

``` python
terminal("""curl -v -X POST https://API.example.com/endpoint \\

-H 'Content-Type: application/JSON' \\
-d '\\\{"key":"value"}' 2>&1""")

`
``**Loại nội dung / nội dung không khớp — 415/400 im lặng:**

``` python

# WRONG — data= sends form-encoded, header lies
requests.post(url, data='\\\{"k":"v"}', headers=\\\{"Content-Type": "application/JSON"})

# RIGHT — JSON= auto-sets header AND serializes
requests.post(url, JSON=\\\{"k": "v"})

# WRONG — Accept says XML, code calls .JSON()
requests.get(url, headers=\\\{"Accept": "text/xml"})

# RIGHT — let requests build multipart with boundary
requests.post(url, files=\\\{"file": open("doc.pdf", "rb")})

`
``Phổ biến: được mã hóa biểu mẫu so với JSON, thiếu trường bắt buộc, phương thức HTTP sai, thông số truy vấn không được mã hóa.

### Bước 5 - Phân tích phản hồi

Luôn kiểm tra loại nội dung trước khi gọi

.JSON()

:

``` python
execute_code('''
import requests
resp = requests.post(url, JSON=payload, timeout=10)
print(f"status=\\\{resp.status_code}")
print(f"headers=\\\{dict(resp.headers)}")
ct = resp.headers.get("Content-Type", "")
if "application/JSON" in ct:
print(resp.JSON())
else:
print(f"unexpected content-type \\\{ct!r}, body=\\\{resp.text[:500]!r}")
''')

`
``Lỗi: Trang lỗi HTML có JSON dự kiến, nội dung trống, bộ ký tự sai.

### Bước 6 - Xác thực ngữ nghĩa

Được phân tích cú pháp rõ ràng — nhưng dữ liệu có *chính xác* không?
-

"status": "active"
` có nghĩa là mã của bạn nghĩ gì không?

- ID phản hồi có khớp với ID được yêu cầu không?
- Dấu thời gian trong múi giờ dự kiến?
- Phân trang trả về tất cả kết quả, hay chỉ trang 1?

## Cẩm nang trạng thái HTTP

### 401 Không được phép - thông tin xác thực bị thiếu hoặc không hợp lệ
1. Tiêu đề
`Authorization
` thực sự có mặt? (
`curl -v
` để xác nhận)
2. Token chính xác và chưa hết hạn?
3. Sơ đồ xác thực đúng không? (
`Bearer
` so với
`Basic
` so với
`Token

)
4. Một số API sử dụng tham số truy vấn (

?API_key=

) thay vì tiêu đề.

### 403 Bị cấm — được xác thực nhưng không được ủy quyền
1. Mã thông báo có phạm vi/quyền cần thiết không?
2. Tài nguyên thuộc sở hữu của một tài khoản khác?
3. Danh sách IP cho phép chặn bạn?
4. CORS trong trình duyệt? (kiểm tra
`Access-Control-Allow-Origin

)

### 404 Not Found — tài nguyên không tồn tại hoặc URL sai1. Đường dẫn có đúng không? (dấu gạch chéo, lỗi đánh máy, tiền tố phiên bản)
2. ID tài nguyên có tồn tại không?
3. Phiên bản API phù hợp (

/v1/
` so với

/v2/

)?
4. URL cơ sở phù hợp (dàn dựng so với sản phẩm)?

### 409 Xung đột — xung đột trạng thái
1. Tài nguyên đã tồn tại (tạo trùng lặp)?
2.
`ETag
` /
`If-Match
` cũ?
3. Sửa đổi đồng thời bởi một quy trình khác?

### 422 Thực thể không thể xử lý - JSON hợp lệ, dữ liệu không hợp lệ

Phần thân lỗi thường đặt tên cho các trường xấu. Kiểm tra:
- Các loại trường (chuỗi so với int, định dạng ngày)
- Bắt buộc và tùy chọn
- Giá trị Enum bên trong tập hợp được phép

### 429 Quá Nhiều Yêu cầu — tỷ lệ bị giới hạn

Kiểm tra các tiêu đề
`Retry-After
` và
`X-RateLimit-*

. Độ lùi theo cấp số nhân:

``` python
execute_code('''
import time, requests`def with_backoff(method, url, **kwargs):
for attempt in range(5):
resp = requests.request(method, url, **kwargs)
if resp.status_code != 429:
return resp
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
return resp
''')

`

### 5xx — phía máy chủ, thường không phải lỗi của bạn
- **500** — lỗi máy chủ. Chụp ID tương quan, gửi hồ sơ cho nhà cung cấp.

- **502** — ngược dòng xuống. Rút lui + thử lại.
- **503** — quá tải/bảo trì. Kiểm tra trang trạng thái.
- **504** — hết thời gian chờ ngược dòng. Giảm tải trọng hoặc tăng thời gian chờ.

Đối với tất cả 5xx: lùi lại với jitter, cảnh báo về độ bền.

## Phân trang & Tính bình đẳng`**Phân trang.** Xác minh rằng bạn nhận được *tất cả* kết quả. Hãy tìm
`next_Cursor

,
`next_page

,
`total_count

. Hai mẫu:
- Offset (

?limit=100&offset=200

) — đơn giản, có thể bỏ qua các mục nếu dữ liệu thay đổi.
- Con trỏ (

?Cursor=abc123

) — ưu tiên cho các tập dữ liệu trực tiếp hoặc lớn.

**Idempotency.** Đối với các hoạt động không bình thường (POST), hãy gửi
`Idempotency-Key: <uuid>
` để các lần thử lại không tính phí gấp đôi/tạo hai lần. Bắt buộc phải thanh toán và đặt hàng.

## Xác thực hợp đồng

Nắm bắt sự trôi dạt của lược đồ trước khi nó được đưa vào sản xuất:

``` python
execute_code('''
import requests`def validate_user(data: dict) -> list[str]:
errors = []
required = \\\{"id": int, "email": str, "created_at": str}
for field, expected in required.items():
if field not in data:
errors.append(f"missing field: \\\{field}")
elif not isinstance(data[field], expected):
errors.append(f"\\\{field}: want \\\{expected.__name__}, got \\\{type(data[field]).__name__}")
return errors`resp = requests.get(f"\\\{BASE}/users/1", headers=HEADERS, timeout=10)
issues = validate_user(resp.JSON())
if issues:
print(f"contract violations: \\\{issues}")
''')

`
``Chạy sau khi nâng cấp API, khi tích hợp bên thứ ba mới hoặc trong thử nghiệm khói CI.

## ID tương quan

Luôn nắm bắt ID yêu cầu của nhà cung cấp — con đường nhanh nhất để được hỗ trợ bởi nhà cung cấp:

`Python
execute_code('''
import requests
resp = requests.post(url, JSON=payload, headers=headers, timeout=10)
request_id = (
resp.headers.get("X-Request-Id")
or resp.headers.get("X-Trace-Id")
or resp.headers.get("CF-Ray") # Cloudflare
)
if resp.status_code >= 400:
print(f"failed status=\\\{resp.status_code} req_id=\\\{request_id} ts=\\\{resp.headers.get('Date')}")
''')

`
``**Mẫu báo cáo lỗi của nhà cung cấp:**

`
Endpoint: POST /API/v1/orders
Request ID: req_abc123xyz
Timestamp: 2026-03-17T14:30:00Z
Status: 500
Expected: 201 with order object
Actual: 500 \\\{"error":"internal server error"}
Repro: curl -X POST … (auth: ``<REDACTED>``)

`

## Mẫu kiểm tra hồi quy

Thả cái này vào
`tests/
` và chạy qua
`terminal('pytest tests/test_API_smoke.py -v')

:

`Python
import os, requests, pytest

BASE_URL = os.environ.get("API_BASE_URL", "https://API.example.com")
TOKEN = os.environ.get("API_TOKEN", "")
HEADERS = \\\{"Authorization": f"Bearer \\\{TOKEN}"}`class TestAPISmoke:
def test_health(self):
resp = requests.get(f"\\\{BASE_URL}/health", timeout=5)
assert resp.status_code == 200`def test_list_users_returns_array(self):
resp = requests.get(f"\\\{BASE_URL}/users", headers=HEADERS, timeout=10)
assert resp.status_code == 200
data = resp.JSON()
assert isinstance(data.get("data", data), list)

def test_get_user_required_fields(self):
resp = requests.get(f"\\\{BASE_URL}/users/1", headers=HEADERS, timeout=10)
assert resp.status_code in (200, 404)
if resp.status_code == 200:
user = resp.JSON()
assert "id" in user and "email" in user`def test_invalid_auth_returns_401(self):
resp = requests.get(
f"\\\{BASE_URL}/users",
headers=\\\{"Authorization": "Bearer invalid-token"},
timeout=10,
)
assert resp.status_code == 401

`

## Bảo mật

### Xử lý mã thông báo

- Không bao giờ đăng nhập toàn bộ token. Làm lại:
`Bearer ``<REDACTED>

.
- Không bao giờ mã hóa mã thông báo trong tập lệnh. Đọc từ env (
`os.environ["API_TOKEN"]

) hoặc

~/.Hermes/.env

.
- Xoay vòng ngay lập tức nếu mã thông báo xuất hiện trong nhật ký, thông báo lỗi hoặc lịch sử git.

### Ghi nhật ký an toàn

``` python
def redact_auth(headers: dict) - dict:
sensitive = \\\{"authorization", "x-API-key", "cookie", "set-cookie"}
return \\\{k: ("``<REDACTED>``" if k.lower() in sensitive else v) for k, v in headers.items()}

`

### Danh sách kiểm tra rò rỉ
- [ ] **Thông tin xác thực trong URL.** Khóa API trong chuỗi truy vấn sẽ xuất hiện trong nhật ký máy chủ, lịch sử trình duyệt, tiêu đề liên kết giới thiệu — sử dụng tiêu đề.

- [ ] **PII trong phản hồi lỗi.**
`404 on /users/123
` không được tiết lộ liệu người dùng có tồn tại hay không (liệt kê).
- [ ] **Xếp chồng dấu vết trong sản phẩm.** 500s không được rò rỉ đường dẫn tệp, phiên bản khung.
- [ ] **Tên máy chủ/IP nội bộ.**
`10.x.x.x

,
`internal-API.corp.local
` trong các nội dung lỗi.
- [ ] **Mã thông báo bị phản hồi.** Một số API bao gồm mã thông báo xác thực trong chi tiết lỗi. Xác minh rằng họ không.
- [ ] **Chi tiết
`Server
` /
`X-Powered-By

.** Rò rỉ thông tin ngăn xếp. Lưu ý để xem xét bảo mật.

## Mẫu công cụ Hermes

### terminal - để cuộn tròn, đào, openSSL

``` python
terminal('curl -sI https://API.example.com')
terminal('openSSL s_CLIent -connect API.example.com:443 -servername API.example.com </dev/null 2/dev/null | openSSL x509 -noout -dates')

`

### exec_code — dành cho các luồng Python nhiều bước

Khi gỡ lỗi kéo dài xác thực → tìm nạp → phân trang → xác thực, hãy sử dụng
`execute_code

. Các biến vẫn tồn tại cho tập lệnh, kết quả được in ra thiết bị xuất chuẩn, không có nguy cơ spam mã thông báo trong ngữ cảnh của bạn:

`Python
execute_code('''
import os, requests`token = os.environ["API_TOKEN"]
base = "https://API.example.com"
H = \\\{"Authorization": f"Bearer \\\{token}"}

# 1. auth
me = requests.get(f"\\\{base}/me", headers=H, timeout=10)
print(f"auth \\\{me.status_code}")

# 2. paginate
all_users, Cursor = [], None
while True:
params = \\\{"Cursor": Cursor} if Cursor else \\{}
r = requests.get(f"\\\{base}/users", headers=H, params=params, timeout=10)
body = r.JSON()
all_users.extend(body["data"])
Cursor = body.get("next_Cursor")
if not Cursor:
break
print(f"users=\\\{len(all_users)}")
''')

`

### web_extract — dành cho tài liệu API của nhà cung cấp

Kéo thông số kỹ thuật cho điểm cuối mà bạn đang gỡ lỗi thay vì đoán:

`Python
web_extract(urls=["https://docs.example.com/API/v1/users"])

`

### delegate_task — để quét toàn bộ bài kiểm tra CRUD

`Python
delegate_task(
goal="Test all CRUD endpoints for /API/v1/users",
context="""
Follow the rest-graphql-debug skill (optional-skills/software-development/rest-graphql-debug).
Base URL: https://API.example.com
Auth: Bearer token from API_TOKEN env var.

For each verb (POST, GET, PATCH, DELETE):

- happy path: assert status + response schema
- error cases: 400, 404, 422
- log a repro curl for any failure (redact tokens)

Output: pass/fail per endpoint + correlation IDs for failures.
""",
toolsets=["terminal", "file"],
)

`

## Định dạng đầu ra

Khi báo cáo kết quả:

`
## Finding
Endpoint: POST /API/v1/users
Status: 422 Unprocessable Entity
Req ID: req_abc123xyz

## Repro
curl -X POST https://API.example.com/API/v1/users \
-H 'Content-Type: application/JSON' \
-H 'Authorization: Bearer ``<REDACTED>``' \
-d '\\\{"name":"test"}'

## Root Cause
Missing required field
`email

. Server validation rejects before processing.

## Fix
-d '\\\{"name":"test","email":"test@example.com"}'

`

## Liên quan
-
`systematic-debugging
` — sau khi lớp API bị lỗi bị cô lập, hãy tìm nguyên nhân gốc cho mã của bạn
-
`test-driven-development
` — viết bài kiểm tra hồi quy trước khi gửi bản sửa lỗi