搜尋文件

輸入關鍵字,搜尋標題與正文。

    API文件 02/16

    輸入、輸出與失敗語意

    本文提要

    知道參數是字串、結果是整數,還不足以正確使用 API。 同樣一段文字,可能因長度、缺值或編碼規則不同而被接受或拒絕; 同樣收到失敗訊號,也不一定代表操作完全沒有改變資料。

    文件與本文目錄
    本主題文件

    知道參數是字串、結果是整數,還不足以正確使用 API。 同樣一段文字,可能因長度、缺值或編碼規則不同而被接受或拒絕; 同樣收到失敗訊號,也不一定代表操作完全沒有改變資料。

    本文接續〈介面、契約與責任〉, 說明如何讀懂資料限制、驗證、結果與副作用,不預設程式語言、訊息格式或 HTTP 狀態碼。

    查證日期:2026-11-02。官方實例採 JSON Schema Draft 2020-12、Java SE 25, 以及查證當日的 gRPC 官方狀態碼文件;後者是持續更新的文件,未標示固定版本。 本文只查閱文件,未執行程式或服務測試;自創例子是教學規則,不代表既有產品。

    型別以外,還有哪些規則

    型別描述資料屬於哪一類;使用規則還要說明哪些值有效,以及如何解讀它們。

    表格・2 欄 5 列
    面向需要釐清的問題
    值的範圍整數可以是負數嗎?上下限是否包含邊界?
    單位時間數值代表秒還是毫秒?文字長度按位元組還是其他單位計算?
    文字表示若輸入是位元組,採什麼編碼解讀?是否保留前後空白?
    缺值未提供、明確傳入空值、空字串,分別代表什麼?
    與狀態的關係即使資料形式正確,目前是否允許這項操作?

    「必填」與「不接受空值」是不同限制。 例如 JSON Schema Draft 2020-12 的 required 檢查物件是否具有指定名稱的屬性; 屬性值能否為 null,則還要看型別等限制。 因此,屬性存在但值為 null,可以通過 required,卻不符合只接受字串的型別要求。 參考 JSON Schema:required 與type。 這是 JSON 的具體規則;其他介面的缺值表達方式須另讀自己的文件。

    用「設定清單標題」貫穿觀察

    以下是本站自創的教學例子。假設程式已持有一份可修改的清單,提供這個操作:

    TEXT
    設定清單標題(title) → 成功(舊標題, 新標題) 或 失敗(標題無效)
    

    這是概念偽碼,成功、失敗 是兩種可辨識的結果,不指定實際語法或資料格式。 本例只處理記憶體內的一份清單,不涉及檔案、網路或其他程式同時修改它的情況。

    表格・2 欄 6 列
    項目本例規則
    輸入型別title 必須提供,且為文字字串;不接受空值,也不自動把數字轉為字串
    有效長度1 到 20 個 Unicode 碼位(code points),包含兩端;本例以碼位數定義長度,不以畫面上的字形數計算
    文字處理保留所有輸入文字,不移除空白、不截短,也不做其他轉換;只有空白的字串仍可有效
    輸入有效將標題設為輸入文字,回傳成功;舊標題是呼叫前的值,新標題是設定後的值
    輸入無效未提供、空值、非字串、長度為 0 或超過 20,均回傳 失敗(標題無效)
    狀態影響成功只設定標題,不改變項目內容與順序;上述輸入失敗不改變任何清單資料

    舊標題與新標題相同也算成功;本例沒有把「必須與原值不同」列為限制。 這些規則都是教學設計的選擇,其他 API 可以採取不同規則。

    以下每一列都獨立從標題「待辦」、項目內容相同的清單開始:

    表格・3 欄 5 列
    輸入結果呼叫後的標題
    「讀書」成功(「待辦」, 「讀書」)「讀書」
    「待辦」成功(「待辦」, 「待辦」)「待辦」
    空字串失敗(標題無效)「待辦」
    未提供、空值或數字 123失敗(標題無效)「待辦」
    連續 21 個「甲」失敗(標題無效)「待辦」

    驗證發生在哪個邊界

    驗證(validation)是檢查輸入是否符合已定義的規則。 在本例,提供者先確認輸入存在、型別與長度都有效,才設定標題。 如果先改了標題,再發現長度不符而回傳失敗,就無法履行「輸入失敗時清單不變」的承諾。

    呼叫端也可以先檢查,讓人及早看到錯誤;但當提供者承諾拒絕無效輸入時, 不能只依賴某個畫面的檢查,因為其他程式也可能直接呼叫這個介面。 在靜態型別的程序內 API,部分型別限制可能由編譯器檢查; 是否還需要執行時檢查,要看哪些限制已受保證、哪些輸入仍可能到達該邊界。

    驗證與轉換也應區分。本例遇到 21 個碼位會拒絕,而不是截成 20 個。 若要先移除空白再檢查長度,就必須明訂轉換順序;那會是另一套行為。 若某項限制依賴會變動的狀態,只在很早之前檢查,也不足以保證實際修改時仍然成立。

    輸出值要連同意義一起讀

    本例的成功結果包含兩個字串,但順序與意義不能互換。 「舊標題」取自呼叫前,「新標題」則是這次設定的值;呼叫端不能只看到兩個字串就自行猜測。 同樣地,若某個 API 回傳整數,還要確認它代表數量、位置,或已完成的工作量。

    特殊值尤其需要說明。Java SE 25 的 Map.get(key) 在沒有對應項目時回傳 null; 若該 Map 允許儲存 null,回傳 null 也可能代表「該鍵存在,值就是 null」。 文件指出可用 containsKey 區分這兩種情況。 因此不能把所有 API 的 null 都解讀成失敗,或一律解讀成資料不存在。 參考 Java SE 25:Map.get。

    失敗的原因與表達方式是兩件事

    失敗語意要說明什麼情況算失敗、呼叫端如何辨識,以及失敗後仍有哪些保證。 本例的「標題無效」是已定義的輸入失敗;它不是提供者程式故障的證據。 「預期會遇到的失敗」也不表示一定採用某種語法。

    表格・2 欄 3 列
    表達方式呼叫端如何得知
    結果值本例直接回傳可區分的成功或失敗結果,呼叫端檢查結果種類
    例外Java 的 Integer.parseInt(String) 在字串無法解析成 int 時拋出 NumberFormatException,呼叫端依例外機制處理
    協定資訊gRPC 以包含狀態碼與錯誤描述的 status 表達呼叫結果;語言函式庫再以自己的介面呈現

    Java 的具體行為見 Java SE 25:Integer.parseInt; gRPC 的規則見官方狀態碼文件。 這些表達可以在不同層之間轉換;看到語言中的例外,不能直接推定遠端使用了哪種錯誤格式。 可供程式判斷的結果種類、例外型別或狀態碼,與給人閱讀的說明文字,也應分清楚。 除非文件保證文字是固定的判斷依據,否則不宜只比對一句錯誤描述來決定行為。

    失敗不一定代表狀態未改變

    副作用(side effect)是操作除了產生結果值之外,對可觀察狀態造成的影響, 例如設定標題、改寫檔案或修改集合。它可以是操作的主要目的,並不表示發生了錯誤。

    本例明訂輸入失敗時清單不變,呼叫端才有這項保證。 不能把它擴大成「所有 API 只要回報失敗,就一定什麼都沒做」。 例如 gRPC 官方文件明確說明:對會改變狀態的操作,DEADLINE_EXCEEDED 仍可能出現在操作已成功完成之後, 原因可能是成功回應延遲到期限之後才到達。 參考 gRPC:DEADLINE_EXCEEDED。

    這時,呼叫端知道自己沒在期限內取得成功結果,卻不能只憑這個狀態碼判定服務沒有執行操作。 閱讀失敗規則時,要確認文件是否保證不變、可能已改變,或無法從目前結果確定。 如何確認遠端結果、是否能重試,以及如何避免重複影響,見逾時、重試與冪等性。

    相關文件