sfappAPI 文件

錯誤碼

每個錯誤回應都是同一個外殼,格式與各欄位見 請求慣例

程式依 error.code 分支。錯誤碼在 /v1 之內不改名,也不改對應的 HTTP 狀態;message 的文字會調整。

error.retryable 是下表「可否重試」那一欄的值。true 代表原樣重送有機會成功,false 代表結果不會改變,請改動請求或改變流程。

被限流擋下時,回應帶 Retry-After,值是建議等待的秒數。

狀態碼

狀態碼 意思
200 成功,回應帶內容
201 已建立新資源
204 成功,回應沒有內容
401 金鑰缺少、格式錯誤、已過期或已撤銷
403 金鑰有效,權限範圍不足
404 資源不存在,或商店未開通該功能
409 與資源目前的狀態衝突
413 內文或檔案超過上限
415 不支援的內容型別
422 欄位驗證失敗
429 超過限流、併發或每日配額
500 伺服器發生非預期錯誤
503 商店尚未完成開通,或寫入暫停

錯誤碼一覽

錯誤碼 HTTP 意思 處理動作 可否重試
unauthorized 401 金鑰缺少或無效 檢查 Authorization 是否為 Bearer 加一個空白加金鑰,並確認金鑰未過期
insufficient_scope 403 金鑰少了這支端點要的權限範圍 detailsissue(值為 required: 加權限名),向矽羽申請具該權限的金鑰
not_found 404 找不到這個資源 核對路徑與識別碼;別家商店的資源一律回這個碼
feature_unavailable 404 商店未開通這個功能 先讀 GET /v1/mefeatures 再決定是否呼叫;開通請聯絡矽羽
validation_failed 422 請求欄位不合法 detailsfieldissue 逐欄修正後重送
title_charset_unsupported 422 標題含這家商店存不下的字元 移除 details 指出的字元;事前判斷看 limits.title_allows_emoji
cover_image_not_owned 422 封面網址不屬於這家商店 先用 POST /v1/media/images 上傳,再把回應的 url 原樣填入
content_too_large 413 內文超過這家商店的上限 縮短 body_html 或拆成多篇;上限看 limits.body_max_bytes
image_too_large 413 圖片檔案或像素超過上限 在本地縮小後再上傳;上限見 限制與配額
unsupported_media_type 415 上傳的內容不是支援的圖片格式 轉成 limits.image_formats 列出的格式再上傳
idempotency_key_reused 409 同一把冪等鍵先前用在不同的內容上 重試時送出與第一次完全相同的內容;新的建立換一把新的鍵
idempotency_in_progress 409 同一把冪等鍵的前一次請求還在處理 Retry-After(約 2 秒)重送,鍵與內容都保持原樣
duplicate_content 409 十分鐘內已有標題與內文相同的文章 沿用 details 指出的既有文章
confirmation_required 409 刪除需要第二段確認 文章 的刪除端點送第二次請求
post_is_published 409 已發布或已排程的文章不能刪除 先呼叫下架端點,再刪除
post_has_product_links 409 文章仍關聯著商品 請人在商店後台解除關聯後再刪除
category_name_conflict 409 同一個父分類底下已有同名分類 沿用 details 附的既有分類識別碼,或改用別的名稱
image_in_use 409 圖片仍被文章當封面或在內文引用 PATCH /v1/blog/posts/{id} 換掉 details 所列文章的引用,再刪一次
rate_limited 429 這一分鐘的讀或寫次數用完 Retry-After 等待後重送,退避時加隨機抖動並設重試次數上限
concurrency_limited 429 同時處理中的請求數超過上限 Retry-After(約 1 秒)重送,並降低併發
quota_exceeded 429 今日新增文章或上傳圖片的配額用完 停止重試,改到隔天執行或減少每天的量;用量查 GET /v1/mequotas
tenant_not_certified 503 商店尚未完成開通 聯絡矽羽完成開通,期間讀取與寫入都會被擋
tenant_schema_changed 503 商店的內容結構已變更,寫入暫停 聯絡矽羽確認;期間讀取仍可用
internal_error 500 伺服器發生非預期錯誤 退避後重試數次,連續失敗就停下來告警;持續發生時把 request_id 提供給矽羽

處理錯誤

import os

import requests

BASE_URL = "https://api.sfec.cloud"

response = requests.get(
    f"{BASE_URL}/v1/blog/posts",
    headers={"Authorization": f"Bearer {os.environ['SFAPP_KEY']}"},
    params={"limit": 5},
    timeout=10,
)
if response.ok:
    print("取得", len(response.json()["data"]), "篇文章")
else:
    error = response.json()["error"]
    print("錯誤碼:", error["code"])
    print("追蹤碼:", error["request_id"])
    for item in error["details"]:
        print(" -", item["field"], item["issue"])
    if error["retryable"]:
        print("建議等待秒數:", response.headers.get("Retry-After", "自行退避"))