背景
在实际项目中,经常需要在 Shopify 商店发生特定事件时能够自动接收到通知。这些事件可以是新订单的创建、产品的添加、购物车的更新等等。好在 Shopify 本身向开发者提供了丰富的 Webhooks 列表,当你在 Shopify 应用中订阅了特定的事件后,一旦这些事件发生,Shopify 就会向你指定的 URL 发送包含事件详情的数据。这些数据通常以 JSON 格式发送,易于解析和处理。
本文主要总结了本人在实际项目中实践过的3种订阅 Shopify Webhook 的方式。
目录
- 准备工作
- 方案一:Shopify 商店后台配置
- 方案二:shopify.app.toml 配置
- 方案三:GraphQL Admin API 配置
- 相关拓展
准备工作
Webhook 测试地址
因为国内的网络问题,我们在使用内网穿透工具启动本地服务时, Shopify 通过内网穿透的形式无法正常访问我们本地的服务,因此会导致 Webhook 订阅失败。
本文主要聚焦于 Shopify Webhook 本身的功能,而非网络服务问题的解决,因此这里推荐给大家一个免费的可以用于测试的 Webhook 站点工具,以此来确认是否成功的订阅了 Shopify 的 Webhook,站点工具地址是:webhook.site/。
进入网站,获取到测试的 Webhook 地址,示例如下:
Shopify 应用权限
为了保证我们能够正常的订阅到 Shopify 中的事件,我们需要确认是否拥有要订阅的事件对应的权限,相关权限可以参考下面两个文档进行确认:
- Webhook List :shopify.dev/docs/api/we…
- Access Scopes:shopify.dev/docs/api/us…
实际业务中,在我们决定要订阅不同的 Webhook 事件之前,一定要先保证我们已经配置了相应事件的权限,否则会导致无法正常订阅。
配置权限,可以在 Shopify App 项目的 shopify.app.toml
文件中,配置示例如下:
[access_scopes]
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
scopes = "write_products"
需要注意的是,每当修改了 shopify.app.toml
文件中的任意内容时,必须将其发布到 Shopify 后台中,否则将没有任何效果。可以使用 shopify app deploy
推送新的配置。
tips: 由于本文重点在于如何配置 Webhook 订阅,因此针对如何设置权限,不过多讨论。
方案一:Shopify 商店后台配置
-
登录你的商店后台,即:
https://admin.shopify.com/store/xxx
。 -
进入左侧“设置”->“通知”->“Webhook”。
-
进入 webhook 测试站点,复制系统随机生成的 webhook 地址,并保持页面不要关闭,方便随时查看接口响应。
-
在 Shopify 的 Webhook 页面中,新增一个订阅事件,并将刚才复制的 URL 填进去。
-
添加完成后,可以点击“发送测试”按钮,查看是否订阅成功
-
如果不出意外,我们将在 webhook.site 站点收到刚才的测试请求:
-
为了验证我们的 Webhook 订阅成功,我们可以手动的创建一个产品,再次验证这个 Webhook
-
创建一个用于测试的产品
-
如果不出意外,我们已经收到了 Webhook 数据
-
至此,我们实现了最简单的 Webhook 订阅配置,此方法的优缺点也很明显:
- 优点:操作简单,不需要涉及代码开发
- 缺点:仅支持一些基础的 Webhook 事件,不能覆盖 Shopify 全部的 Webhooks 事件列表
方案二: shopify.app.toml 配置
在测试之前,请确保你的 shopify.app.toml
配置中已设置好所需的 [access_scopes]
。
打开 Shopify App 项目的 shopify.app.toml
文件,以创建产品这个事件为例,订阅 Webhook 的配置如下:
[webhooks]
api_version = "2024-07"
[[webhooks.subscriptions]]
topics = [ "products/create"]
uri = "https://webhook.site/9523687d-5460-41b4-9093-d8a3d13e6dce"
配置说明:
- webhooks 需要设置对应的 api_version 版本,建议使用最新的稳定版。
- webhooks.subscriptions 设置需要订阅的 Shopify 事件
- topics 为所有订阅事件的数组,全部事件可以参考文档 webhook topics list
- uri 为订阅 webhook 的地址,此处依然采用测试地址,可以根据实际情况改成业务地址
配置完成后,通过 shopify app dev --reset
重置一遍配置文件,并选择项目为已存在项目,之后才会正常触发修改后的 webhook 订阅。
由于订阅效果跟方案一相同,因此就不重复贴示例图了。
方案三:GraphQL Admin API 配置
除了使用配置文件外,我们也可以通过代码的方式,在项目运行阶段,动态的设置 Webhook。
具体实现是在 shopify.server.ts
文件中,示例代码如下:
import "@shopify/shopify-app-remix/adapters/node";
import {
ApiVersion,
AppDistribution,
DeliveryMethod,
shopifyApp,
} from "@shopify/shopify-app-remix/server";
import { PrismaSessionStorage } from "@shopify/shopify-app-session-storage-prisma";
import { restResources } from "@shopify/shopify-api/rest/admin/2024-07";
import prisma from "./db.server";
const shopify = shopifyApp({
apiKey: process.env.SHOPIFY_API_KEY,
apiSecretKey: process.env.SHOPIFY_API_SECRET || "",
apiVersion: ApiVersion.July24,
scopes: process.env.SCOPES?.split(","),
appUrl: process.env.SHOPIFY_APP_URL || "",
authPathPrefix: "/auth",
sessionStorage: new PrismaSessionStorage(prisma),
distribution: AppDistribution.AppStore,
restResources,
// 重点是 webhooks 和 hooks 部分
webhooks: {
PRODUCTS_CREATE: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: "https://webhook.site/9523687d-5460-41b4-9093-d8a3d13e6dce",
},
},
hooks: {
afterAuth: async ({ session }) => {
shopify.registerWebhooks({ session });
},
},
future: {
unstable_newEmbeddedAuthStrategy: true,
},
...(process.env.SHOP_CUSTOM_DOMAIN
? { customShopDomains: [process.env.SHOP_CUSTOM_DOMAIN] }
: {}),
});
export default shopify;
export const apiVersion = ApiVersion.July24;
export const addDocumentResponseHeaders = shopify.addDocumentResponseHeaders;
export const authenticate = shopify.authenticate;
export const unauthenticated = shopify.unauthenticated;
export const login = shopify.login;
export const registerWebhooks = shopify.registerWebhooks;
export const sessionStorage = shopify.sessionStorage;
- 代码说明:
- 跟 webhook 相关的代码,主要是
webhooks
和hooks
两部分hooks
可以保持不变,除非你了解其中逻辑webhooks
中则是具体的事件订阅设置
- 其中
PRODUCTS_CREATE
跟 webhook topics list中的products/create
对应,但注意需要大写 - deliveryMethod 固定设置 DeliveryMethod.Http 即可
- callbackUrl 为订阅 webhook 的接口地址
- 跟 webhook 相关的代码,主要是
配置完成后,通过 shopify app dev --reset
重置一遍配置文件,并选择项目为已存在项目,之后才会正常触发修改后的 webhook 订阅。
由于订阅效果跟方案一相同,因此就不重复贴示例图了。
相关拓展
-
如果你仔细阅读过官方文档 shopify.dev/docs/apps/b… ,你会发现官方比较推荐使用 Google Cloud 的 Pub/Sub 或者是 Amazon EventBridge 来实现 Webhook 订阅。但个人认为除非有特殊要求,否则没有必要再引入一个技术链路,因为这意味着整个功能的链路额外增加了一层,当我们遇到问题时,将更难确定是哪一层出现了问题。
-
我们在开发 Shopify App 时,本身就启动了一个基于 Remix.js 的 Node.js 服务,因此我们可以考虑用这个服务来接收 Shopify 的 Webhook 事件,而且实践起来也比较简单,感兴趣的同学可以尝试,这里将核心关键点列举出来:
- 只支持方案二和方案三,将对于的 uri 改为相对路径如:
/webhooks
- 在 Shopify App 的 Remix.js 服务中,增加一个
/webhooks
路由 - 在这个路由中即可获取到 Shopify 的 Webhook 订阅事件
- 需要注意,国内的穿透服务可能无法支持这种用法,这个跟网络有关,可以用
shopify app dev
启动,而不要设置指定的隧道域名,或是尝试海外的ngrok
穿透服务
- 只支持方案二和方案三,将对于的 uri 改为相对路径如:
-
我们可以在
https://partners.shopify.com/
后台,看到 Webhook 日志,这方便我们排查 Webhook 发送失败的原因。 -
还有更多关于 Webhook 的内容,比如发送失败的重连次数,是否有重复订阅的 Webhook 的校验等,感兴趣的同学可以查阅官方文档
参考文档
- Webhook 测试站点:webhook.site/
- Shopify 支持的 Webhooks 列表:shopify.dev/docs/api/we…
- Shopify Access scopes : shopify.dev/docs/api/us…
- 管理 Webhook 订阅:shopify.dev/docs/apps/b…
浏览知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。