Skip to main content

Resolver 錯誤會以 HTTP 200 傳回

這是撰寫錯誤處理前最需要了解的一件事。 依照 GraphQL over HTTP 規範,抵達我們 resolver 的請求即使操作失敗也會傳回 HTTP 200。失敗會在回應 body 中回報,而不是透過狀態碼。 因此,以下這種檢查方式是無效的:
請改為檢查 body。少數傳輸錯誤(例如不支援的 Content-Type 所造成的 415)的 body 是空的,因此在解析之前,請先確認回應是 JSON:
有些失敗會在任何東西執行之前就被攔截。這些失敗都不會抵達 resolver,也不會使用 API 呼叫:
  • 格式錯誤的請求會傳回錯誤狀態:無效的 JSON 或缺少 query 時為 HTTP 400,body 超過 64 KB 時為 413,使用 POST 以外的方法時為 405,不支援的 Content-Type 則為 415。
  • 不符合 schema 的查詢,只有在你的請求傳送 Accept: application/graphql-response+json 時才會傳回 HTTP 400。這包括語法錯誤、未知的欄位、錯誤的引數型別、無效的列舉值,以及超過查詢限制的查詢。如果你傳送 Accept: application/json 或未傳送 Accept header,同樣的錯誤會傳回 HTTP 200。無論哪種情況,body 都會包含 errors 陣列,且沒有 data。
一旦開始執行,resolver 層級的輸入驗證與 API 失敗(包括驗證、授權、上游速率限制與上游 5xx 回應)都會傳回 HTTP 200 以及 errors 陣列。

錯誤結構

每個 resolver 錯誤都會在 extensions 中帶有類似 HTTP 的 API 狀態:
  • message:人類可讀的說明。我們會從 resolver 錯誤訊息中移除 API Key 與其他憑證,但與你傳送的值有關的錯誤(例如型別錯誤的變數)可能會重複該值。記錄 message 之前,請將它視為可能含有敏感資訊。
  • path:查詢中哪個欄位失敗。當一次請求中有多個欄位時,你可以藉此判斷是哪一個。
  • extensions.status:對應的 REST 呼叫原本會傳回的 HTTP 狀態。請依此進行分支處理。
  • extensions.code:Ayrshare 的數字錯誤代碼,在底層端點有提供時才會出現。
  • extensions.retryAfter:當上游配額或速率限制造成的 429 有可用的重試延遲時才會出現。每次請求的分派預算所造成的 429 不會包含此欄位。
請搭配錯誤代碼參考使用 extensions.code,或將它傳給 explainError。

部分成功

如果一次請求要求多項資料,而只有部分成功,你會同時收到 data 與 errors:
history 已成功,其資料可以使用。只有 analytics 需要重試。不要因為出現 errors 就捨棄整個回應,否則會丟掉你已經被計費的資料。

多社群網路貼文的部分成功

發布到多個社群網路的貼文,可能在某些社群網路上成功,而在其他社群網路上失敗。這種情況不會以 GraphQL 錯誤回報,因為操作本身是成功的:它完全照你的要求執行,並告訴你發生了什麼。 結果會區分三種結果:
  • postIds:已發布的社群網路及其貼文 URL。僅包含成功的項目。
  • errors:失敗的社群網路及失敗原因。
  • blocked:在嘗試發布之前就被阻止的社群網路,例如在重複發生確定性失敗後,被各社群網路的斷路器阻止。這些與供應商嘗試後傳回錯誤的情況是分開的。
只要任何社群網路失敗,status 就會是 "error",因此它無法可靠地表示沒有任何內容被發布。請讀取 postIds 以了解哪些已發布。

重試

GraphQL API 從不自動重試。 如果請求失敗,系統不會在背後代替你悄悄再次嘗試。 這一點對 mutation 最為重要。createPost 提供 idempotencyKey:請在第一次嘗試前產生一個唯一的 key,之後每次重試都重複使用相同的 key 與完全相同的 payload。已完成的重試會重播原始結果,而不會重複寫入。收到不明確的回應後,請不要改用新的 key。 boostFacebookPost 與 instagramBoostPost 也接受 idempotencyKey,而它保護的是真金白銀。使用相同 key 與相同引數的重試會傳回原始結果,並標示 idempotentReplayed: true,而不會建立第二則廣告並再次付費。一個 key 涵蓋你整個帳號在兩個 Meta 平台上的使用,因此絕對不要將 Facebook 推廣的 key 重複用於 Instagram 推廣。 當 key 被拒絕時,extensions.status 會告訴你原因。當第一次嘗試仍在處理中時,createPost 會傳回 409,此時請等待並使用相同的 key 重試;當 payload 與第一次嘗試不同時,則會傳回 400。推廣 mutation 在這兩種情況下都會傳回 409,當該 key 已用於另一個平台的推廣時也是如此。 其他寫入操作(例如 addComment)沒有冪等 key。如果它們的回應遺失,請先檢查社群網路或 API 狀態,再決定是否可以安全地再次嘗試。 有兩種不同的限制都會回報 429,且需要不同的處理方式。分派預算只會在同一個請求中已開始五次 API 呼叫後才拒絕根欄位,其訊息開頭為 Query exceeds the per-request dispatch budget:請將這些欄位拆分成每次最多五個的請求,不需要等待。其他任何 429 都是速率限制或配額:如果有 extensions.retryAfter,請等待該秒數,否則請先退避再重試,且只重試失敗的欄位。對於讀取操作的 5xx,重試是安全的,但有一個例外:generatePost 雖然是 query,但重試會再次呼叫 AI 產生器、再算一次 API 呼叫,並傳回不同的文字。對於沒有冪等性的寫入操作的 5xx,請在重試前先確認它是否已生效。

常見狀態

GraphQL 本身在執行前引發的錯誤(例如未知的欄位、錯誤的引數型別或無效的列舉值)沒有 extensions.status。它們會依你的 Accept header 傳回 HTTP 400 或 200,如上所述。這表示查詢本身有誤,且未進行任何 API 呼叫,也不會計費。