變換函數
「映射」會從請求中擷取值。而「轉換函式」的功能則更進一步:它是您自行撰寫的 JavaScript 程式碼,會在每個請求送至 Shopify Flow 之前執行,因此您可以重新塑形請求內容、進行資料查詢、判斷該請求是否值得觸發工作流程,或是直接自行回應呼叫者。
它位於 webhook 的「函式」索引標籤中。若編輯器為空,則表示已關閉。
函數的形狀
export default async function transform(payload, ctx) {
// payload - the parsed request body (JSON, form or XML)
// return an object -> it becomes the payload for mapping and Flow
// return null -> nothing is sent to Flow, and nothing counts
return { ...payload, source: "warehouse" }
}ctx 能為您帶來什麼
ctx.request |
method、contentType、請求 headers(機密資訊已遮蔽)以及 query |
ctx.webhook |
該 webhook 的 id 和 name |
ctx.shop |
您的 myshopify 網域 |
ctx.log(...) |
在測試面板和「歷史紀錄」中寫入一行您能讀取的內容 |
await ctx.fetch(url, init) |
呼叫一個公開的 API |
await ctx.shopify(query, variables) |
使用 Admin GraphQL 讀取儲存資料 |
ctx.storage |
在不同執行次數之間保留小數值(詳見下文) |
ctx.respond(body, options) |
立即接聽來電 |
重新塑造有效載荷
最常見的用途:將發送方的結構轉換為您的工作流程所需的幾個值。
export default async function transform(payload) {
const order = payload.data.attributes
return {
orderNumber: String(order.number),
email: order.customer.email.toLowerCase(),
total: Number(order.total_cents) / 100,
}
}刪除不需要的請求
回傳 null,請求便在此處終止:不會執行 Shopify Flow,不會產生歷史紀錄,也不會從您的方案配額中扣除任何用量。呼叫方會收到 200 並附帶 { "skipped": true },因此不會進行重試。
export default async function transform(payload, ctx) {
if (payload.status !== "paid" || payload.total < 100) {
ctx.log("skipping", payload.id, payload.status, payload.total)
return null
}
return payload
}在兩次跑步之間記住事情
ctx.storage 這是一個屬於您商店的小型鍵值儲存系統。它是用來回答「我之前見過這個嗎?」的工具:當事件發生時儲存一個 ID,並跳過攜帶相同 ID 的下一個請求,即使該請求是在數天後發送的。
| 致電 | 是否 |
|---|---|
await ctx.storage.get(key) |
儲存值,或稱null |
await ctx.storage.set(key, value) |
儲存任何 JSON 值,並覆寫原有內容 |
await ctx.storage.delete(key) |
將其移除;若該檔案存在,則執行 true |
await ctx.storage.list({ prefix, limit, cursor }) |
各頁的重要名稱與尺寸 |
export default async function transform(payload, ctx) {
const key = `seen:${payload.id}`
if (await ctx.storage.get(key)) return null
await ctx.storage.set(key, { at: Date.now() })
return payload
}透過店舖資料進行資料增強
ctx.shopify 該功能會針對您的商店執行唯讀的 Admin GraphQL 查詢,因此工作流程可以基於發送者從未擁有的資料開始運作。發送者僅能看到您允許的內容:請在「Function」分頁的**「Store 資料存取」**下授予您所需的權限範圍。預設情況下不會授予任何權限,且會拒絕所有變異操作。
export default async function transform(payload, ctx) {
const data = await ctx.shopify(
`query($q: String!) {
productVariants(first: 1, query: $q) { nodes { id title price } }
}`,
{ q: `sku:${payload.sku}` },
)
const variant = data.productVariants.nodes[0]
if (!variant) return null
return { sku: payload.sku, variantId: variant.id, price: variant.price }
}親自接聽來電
ctx.respond() 會立即傳回回應,這使得 webhook 變成一個小型 API 端點:驗證某項內容、計算出結果,並在單一請求中回覆。無論您傳回什麼內容,Shopify Flow 仍會繼續執行。
export default async function transform(payload, ctx) {
const ok = typeof payload.email === "string" && payload.email.includes("@")
ctx.respond({ accepted: ok }, { status: ok ? 200 : 422 })
return ok ? payload : null
}測試
「函式」分頁中的「測試」面板會將編輯器中的程式碼(包含未儲存的變更)套用至範例載荷進行執行。它會顯示回傳值、您的函式會傳送的回應、其產生的Shopify Flow欄位、您的日誌記錄以及執行時間。 此過程不會觸發「Shopify Flow」、不會寫入「歷史紀錄」,也不會計入您的方案配額。不過儲存庫呼叫是真實的:測試執行時會像實際請求一樣讀取和寫入相同的儲存庫。
當函式執行失敗時
如果您的程式碼發生拋出異常、超時或傳回無法使用的結果,系統會以「422」狀態拒絕該請求,並將失敗記錄在**「歷史紀錄」**中,包含錯誤訊息及您的日誌內容,以便您了解發生了什麼情況。修正程式碼後,重新執行該記錄:重新執行時將運行新版本的程式碼。
限制
- 每次執行需時 5 秒,佔用 64MB 空間,且程式碼長達 50,000 個字元。
- 沒有 npm 套件。
ctx.fetch是唯一的解決方案,且系統會拒絕內部或私人位址。 ctx.shopify每次執行允許進行 10 次呼叫,僅限查詢,且僅限於您已授予的權限範圍內。- 每次執行並成功呼叫 Shopify Flow 的操作,均視為正常呼叫,並計入您的方案配額;被跳過的請求則不計入。

