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

The contractjavascript
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.

Flatten and normalisejavascript
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.

Only paid orders above 100javascript
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
Skip events you have already seenjavascript
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.

Look up a variant by SKUjavascript
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.

Reply to the caller and start a workflowjavascript
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.shopify permite 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.