Fonctions de transformation

La cartographie extrait des valeurs d'une requête. Une fonction de transformation va plus loin : il s'agit de votre propre code JavaScript, exécuté sur chaque requête avant l'appel à Shopify Flow. Vous pouvez ainsi remodeler le payload, effectuer une recherche, déterminer si la requête justifie ou non l'exécution d'un workflow, ou encore répondre vous-même à l'appelant.

Cette option se trouve dans l'onglet « Fonction » d'un webhook. Si l'éditeur est vide, cela signifie que la fonction est désactivée.

La forme d'une fonction

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" }
}

Ce que vous offre ctx

ctx.request method, contentType, la requête headers (informations confidentielles masquées) et query
ctx.webhook Les URL du webhook : id et name
ctx.shop Votre domaine myshopify
ctx.log(...) Affiche une ligne que vous pouvez lire dans le panneau de test et dans l'historique
await ctx.fetch(url, init) Appelle une API publique
await ctx.shopify(query, variables) Lit les données des boutiques à l'aide d'Admin GraphQL
ctx.storage Conserve les petites valeurs d'une exécution à l'autre (voir ci-dessous)
ctx.respond(body, options) Répond immédiatement à la personne qui appelle

Remaniement d'un payload

L'utilisation la plus courante : convertir la structure d'un expéditeur en quelques valeurs dont votre workflow a besoin.

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,
  }
}

Supprimer les requêtes dont vous n'avez pas besoin

La réponse null est renvoyée et la requête s'arrête là : aucune exécution de flux, aucune entrée dans l'historique et rien n'est décompté de votre forfait. L'appelant reçoit la réponse 200 avec le message { "skipped": true }, ce qui l'empêche de réessayer.

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
}

Se souvenir de certaines choses entre deux séances

ctx.storage Il s'agit d'un petit système de stockage clé-valeur propre à votre boutique. C'est l'outil qui vous permet de vous demander : « Ai-je déjà vu cela ? » : enregistrez un identifiant lorsqu'un événement se produit, puis ignorez la requête suivante portant le même identifiant, même si elle arrive plusieurs jours plus tard.

Appel Est-ce que
await ctx.storage.get(key) La valeur stockée, ou null
await ctx.storage.set(key, value) Enregistre n'importe quelle valeur JSON, en écrasant la valeur existante
await ctx.storage.delete(key) Le supprime ; true s'il existait
await ctx.storage.list({ prefix, limit, cursor }) Noms et tailles des éléments clés, page par page
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
}

Enrichissement à l'aide des données des boutiques

ctx.shopify exécute des requêtes GraphQL d'administration en lecture seule pour votre boutique ; ainsi, un workflow peut démarrer avec des données dont l'expéditeur n'a jamais disposé. Il n'a accès qu'à ce que vous autorisez : accordez les périmètres d'accès dont vous avez besoin dans la section «** Accès aux données de la boutique** », sous l'onglet « Fonction ». Aucun accès n'est accordé par défaut, et les mutations sont refusées.

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 }
}

Répondre vous-même à l'appelant

ctx.respond() renvoie immédiatement une réponse, ce qui transforme le webhook en un petit point de terminaison d'API : valider quelque chose, calculer une réponse et renvoyer celle-ci en une seule requête. Shopify Flow continue de fonctionner quel que soit le résultat que vous renvoyez.

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
}

Tests

Le panneau « Test » de l’onglet « Fonction » exécute le code présent dans l’éditeur, y compris les modifications non enregistrées, sur un exemple de payload. Il affiche la valeur de retour, la réponse que votre fonction enverrait, les champs Shopify Flow qu’elle génère, vos lignes de journalisation et la durée. Aucun événement ne déclenche Shopify Flow, rien n’est enregistré dans l’historique et rien n’est comptabilisé dans votre forfait. Les appels au stockage sont toutefois réels : un test lit et écrit dans le même magasin que les requêtes en production.

Lorsqu'une fonction échoue

Si votre code génère une exception, expire ou renvoie un résultat inutilisable, la requête est rejetée avec le message 422 et l'échec est consigné dans l'historique avec le message d'erreur et vos lignes de journal, ce qui vous permet de comprendre ce qui s'est passé. Corrigez le code et relancez cette entrée : la relance s'effectuera avec la nouvelle version.

Limites

  • 5 secondes et 64 Mo par exécution, ainsi que 50 000 caractères de code.
  • Aucun paquet npm. ctx.fetch est la seule solution, et les adresses internes ou privées sont refusées.
  • ctx.shopify autorise 10 appels par exécution, pour les requêtes uniquement, dans la limite des périmètres d'accès que vous avez accordés.
  • Chaque exécution qui parvient à Shopify Flow constitue une invocation normale et est prise en compte dans votre forfait. Une requête ignorée ne l'est pas.