Funções de transformação
O mapeamento extrai valores de um pedido. Uma função de transformação vai mais além: trata-se do seu próprio código JavaScript, executado em cada pedido antes de Shopify Flow, para que possa reestruturar a payload, consultar alguma informação, decidir se vale a pena executar um fluxo de trabalho para esse pedido ou responder diretamente ao autor do pedido.
Encontra-se no separador «Função» de um webhook. Um editor vazio significa que está desativado.
A forma de uma função
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" }
}O que o ctx lhe oferece
ctx.request |
method, contentType, o pedido headers (informações confidenciais ocultadas) e query |
ctx.webhook |
The webhooks id e name |
ctx.shop |
O seu domínio myshopify |
ctx.log(...) |
Escreve uma linha que pode ser lida no painel de teste e no Histórico |
await ctx.fetch(url, init) |
Chama uma API pública |
await ctx.shopify(query, variables) |
Lê os dados da loja com o Admin GraphQL |
ctx.storage |
Mantém os valores pequenos entre execuções (ver abaixo) |
ctx.respond(body, options) |
Atende imediatamente a chamada |
Reestruturar um payload
A utilização mais comum: transformar a estrutura de um remetente nos poucos valores de que o seu fluxo de trabalho necessita.
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,
}
}Eliminar os pedidos de que não necessita
Se devolver null, o pedido termina aí: não há execução do Shopify Flow, não há registo no histórico e nada é contabilizado no seu plano. O chamador recebe 200 com { "skipped": true }, pelo que não volta a tentar.
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
}Recordar coisas entre corridas
ctx.storage é uma pequena loja de pares chave-valor que pertence à sua loja. É a ferramenta ideal para responder à pergunta «Já vi isto antes?»: guarde um ID quando um evento ocorrer e ignore o próximo pedido que contenha o mesmo ID, mesmo que este chegue dias mais tarde.
| Chamada | Será que |
|---|---|
await ctx.storage.get(key) |
O valor armazenado, ou null |
await ctx.storage.set(key, value) |
Armazena qualquer valor JSON, substituindo o valor existente |
await ctx.storage.delete(key) |
Elimina-o; true, caso existisse |
await ctx.storage.list({ prefix, limit, cursor }) |
Principais nomes e tamanhos, página a página |
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
}Enriquecimento com dados da loja
ctx.shopify Executa consultas GraphQL de administração apenas de leitura para a sua loja, pelo que um fluxo de trabalho pode iniciar com dados aos quais o remetente nunca teve acesso. Apenas vê o que o senhor autorizar: conceda os âmbitos de que necessita na secção «Acesso aos dados da loja», no separador «Função». Por predefinição, nada é concedido e as mutações são recusadas.
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 }
}Atender a chamada pessoalmente
ctx.respond() envia uma resposta imediatamente, o que transforma o webhook num pequeno ponto final de API: valida algo, calcula uma resposta e responde numa única solicitação. O Shopify Flow continua a funcionar com o que quer que devolva.
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
}Testes
O painel «Teste», no separador «Função», executa o código no editor, incluindo alterações não guardadas, utilizando um payload. Apresenta o valor de retorno, a resposta que a sua função enviaria, os campos do Shopify Flow que gera, as suas linhas de registo e a duração. Nada aciona o Shopify Flow, nada é registado no Histórico e nada conta para o seu plano. No entanto, as chamadas ao armazenamento são reais: uma execução de teste lê e grava no mesmo armazenamento que os pedidos em produção.
Quando uma função falha
Se o seu código gerar um erro, atingir o tempo limite ou devolver algo inutilizável, o pedido é rejeitado com o código de erro 422 e a falha é registada no Histórico, juntamente com o erro e as suas linhas de registo, para que possa verificar o que aconteceu. Corrija o código e reproduza essa entrada: a reprodução executa a nova versão.
Limites
- 5 segundos e 64 MB por execução, e 50 000 caracteres de código.
- Não há pacotes npm. O endereço
ctx.fetché a única solução, e os endereços internos ou privados não são aceites. ctx.shopifypermite 10 chamadas por execução, apenas consultas, limitadas aos âmbitos que concedeu.- Cada execução que chega ao Shopify Flow é considerada uma invocação normal e conta para o seu plano. Uma solicitação ignorada não conta.

