分頁與篩選

清單端點的分頁形狀、篩選規則,以及需要特別注意的例外

View as Markdown

大部分清單端點共用同一套分頁與篩選規則,這裡一次講清楚;各端點頁面只補充自己特有的篩選欄位。

回應形狀

清單端點的回應都是同一個外層:

{
"data": [ ... ],
"totalCount": 137,
"currentPage": 1,
"pageSize": 100,
"totalPages": 2
}

data 是本頁的資料;totalCount 是符合篩選條件的總筆數,涵蓋所有頁,不受目前頁碼影響;currentPage 就是請求帶入的 pagepageSize 是請求帶入的 pageSizetotalPages 等於 totalCount 除以 pageSize 後無條件進位,沒有符合的資料時為 0。

page 與 pageSize

page 從 1 起算。pageSize 的範圍是 1 到 100,省略時預設為 100。

超出範圍會回傳 400,不會被靜默夾擠成合法值。pageSize=500 不會被悄悄改成 100 再繼續執行,而是直接拒絕整個請求:

情況回應
page 小於 1400 invalid_page
pageSize 不在 1–100 之間400 invalid_page_size
page 過大導致內部位移量溢位400 invalid_page

這個設計是刻意的:如果超出範圍的 pageSize 被自動夾回合法值,一支寫死「送 pageSize=500、跑到 data 回傳筆數小於 500 就當作最後一頁」的掃描程式,會在完全沒有察覺的情況下把每一頁都當成 100 筆處理,進度計算全部跑偏,卻不會出現任何錯誤——資料看起來像是抓完了,其實漏了一大截。改成直接回 400,任何寫錯分頁參數的介接程式都會在第一次呼叫就發現問題,而不是在資料對不上帳的時候才發現。

updatedSince:增量同步用的篩選條件

支援增量同步的清單端點都能用 updatedSince 篩「異動時間等於或晚於此刻」的資料。這個邊界是含在內的:異動時間剛好等於你送出的那一刻,該筆資料也會被回傳,不是嚴格的「在此之後」。所以把上一輪掃到的最後一個異動時間直接當成下一輪的 updatedSince,交界處那幾筆會再出現一次——這是預期行為,你端依 id 覆寫即可,不要當成資料異常。

這個值必須是 ISO-8601 格式,並且帶明確的時區位移或 Z——2026-07-01T00:00:00Z 合法,2026-07-01T00:00:00(沒有位移、沒有 Z)會回傳 400 invalid_updated_since,不會被當成任何時區的預設猜測值。

放進網址時要留意百分號編碼:ISO-8601 的 +(例如 +08:00 時區)在 URL 裡有特殊意義,必須編碼成 %2B,否則會被解讀成空白字元;冒號通常也建議編碼成 %3A,避免部分用戶端函式庫或代理誤解析。例如:

updatedSince=2026-07-01T08%3A00%3A00%2B08%3A00

或使用 UTC 的 Z 結尾,不含 +,可以省去這個顧慮:

updatedSince=2026-07-01T00%3A00%3A00Z

updatedSince 進入簽章計算的方式跟其他 query 參數完全相同——canonical string 簽的是實際送出的、已經編碼過的那個字串(含 %3A%2B),不是解碼後的可讀時間。細節見「驗證與簽章」的 path 與 query string 一節。

outerSysCode/name/barcode 的比對方式

支援這些欄位篩選的清單端點上,比對規則並不一致,混用時要特別注意:

  • outerSysCodename:大小寫不敏感的子字串比對。A100 也會比對到 A1000,因為 A1000 這個字串裡包含 A100。如果你只想找到剛好等於某個值的那一筆,篩選之後還是要在自己這端再比對一次完整字串。
  • barcode:精確比對。 只有整段條碼完全相符才會命中,不是子字串比對,這一點與 outerSysCodename 不同。

GET /v1/product-categories 的分頁是例外

商品分類樹的分頁單位是根分類,不是分類列表裡的每一筆節點,跟其他清單端點不一樣:

  • data 最多回傳 pageSize 個根分類,每個根分類底下帶著它全部的子分類——子分類永遠不會被拆到下一頁,一個根分類要嘛整個出現在這一頁,要嘛完全不出現。
  • totalCount 算的是根分類的數量,不是分類總數(根分類數+子分類數)。
  • 因此一頁實際回傳的節點數是「pageSize 個根分類,加上它們各自帶的子分類」,不會剛好等於 pageSize

商品分類樹通常只有兩層、根分類數十個,預設分頁一次通常就能取回整棵樹,建議查一次後在你端快取,不必每次建立或更新商品前都重新查詢。

GET /v1/internal-roles 不分頁

後台角色清單沒有 datatotalCountcurrentPagepageSizetotalPages 這個分頁外層,回應就是一個 data 陣列,裡面是這個租戶可以指派的完整角色清單。一個租戶的角色數量少且固定,這支端點的用途是在建立後台使用者前查一次、在你端快取,不需要分頁機制。