使用 Gadget 从零开发并部署 Shopify App

文章目录

这篇教程不追求一次做出一个复杂 SaaS,而是先完成一个可以验证的真实项目:

Product Sync Manager:把 Shopify 商品同步到 Gadget,并在商品变化时实时更新。

完成后,你会得到一个能够:

  • 安装到 Shopify 开发商店
  • 显示在 Shopify Admin 中
  • 通过 OAuth 完成商店授权
  • 同步历史商品、变体和图片
  • 接收商品创建、修改和删除 Webhook
  • 在 Webhook 后执行自定义逻辑
  • 使用 React 显示商品列表
  • 部署到 Gadget Production

的基础 Shopify App。

说明:Gadget 的页面名称、模型名称和 Action 文件结构可能随模板和版本变化。下面涉及 Gadget 的菜单时,以项目实际显示为准,不要机械照抄固定路径。


一、先看懂应用是怎么工作的

这个项目的整体结构如下:

商家安装应用
      ↓
Shopify OAuth 授权
      ↓
Gadget 保存商店连接
      ↓
Gadget 调用 Shopify Admin API
      ↓
读取商品数据
      ↓
保存到 Gadget 数据库
      ↓
Shopify 发送商品 Webhook
      ↓
Gadget 更新数据库
      ↓
React 页面显示结果

每个部分负责不同工作:

部分作用
Shopify保存商店和商品数据
Gadget提供后端、数据库、授权和部署能力
Admin API让应用读取或修改 Shopify 后台数据
PostgreSQL保存同步后的数据
WebhookShopify 主动通知商品变化
React显示应用界面

可以把它想象成一个机器人助手:

  • Shopify 是商店
  • Gadget 是机器人的身体
  • Database 是机器人的记忆
  • API 是机器人和商店沟通的窗口
  • Webhook 是商店主动打来的电话
  • React 是机器人展示给商家看的界面

二、开始前的准备

开始前准备:

  • Shopify Partners 或 Shopify 开发者账号
  • 一个 Shopify Development Store
  • 一个 Gadget 账号
  • 一个 Shopify App
  • Chrome 浏览器
  • 一个用于测试的开发商店

如果要测试正式安装,还需要一个可安装应用的正式 Shopify 商店。

开发阶段建议使用带测试数据的开发商店。测试数据可以帮助你快速得到:

  • 商品
  • 商品变体
  • 商品图片
  • 客户
  • 订单
  • 库存

不要一开始就直接连接真实商店。开发期间的错误、重复 Webhook 和测试商品可能会影响真实业务。


三、创建 Shopify 开发商店

登录 Shopify Partners 或 Shopify Dev Dashboard,进入开发商店管理页面。

当前后台可能显示为:

Stores → Add store
Create development store
Development stores
Add development store

创建时可以填写:

Store name: cart-transform-testing
Purpose: App development
Test data: Pre-populated test data

创建完成后,商店后台地址通常类似:

https://cart-transform-testing.myshopify.com/admin

记住这个 .myshopify.com 域名,后面安装应用和排查问题时会用到。


四、创建 Shopify App

Shopify 当前的应用管理以 Dev Dashboard 为中心。需要完整应用界面的项目,可以考虑使用 Shopify CLI;主要做数据同步、后台自动化或 API 集成时,也可以直接在 Dev Dashboard 配置应用。

不要把菜单路径写死成某一个版本。常见入口可能包括:

Apps → Create app
Create app manually
Build an app manually

开发应用可以命名为:

Product Sync Manager - Development

创建后记录:

Development Client ID
Development Client Secret

这两个值的作用不同:

  • Client ID:应用的身份编号
  • Client Secret:证明应用身份的秘密钥匙

Client Secret 只能放在服务端或安全的环境变量中,不能:

  • 写入 React 前端
  • 提交到 GitHub
  • 放在公开截图中
  • 复制到博客示例里
  • 直接发给不需要它的人

Shopify 的应用配置还会涉及应用版本、App URL、API 权限和 Webhook API 版本。配置修改后,通常需要创建或发布新的应用版本。citation:Building apps


五、创建 Gadget 项目

登录 Gadget,创建一个新的 Shopify 应用项目。

项目名可以使用:

my-first-shopify-app

建议:

  • 使用英文
  • 使用小写字母
  • 使用连字符
  • 不要包含密码
  • 不要把真实商家的敏感信息写进项目名

创建时选择类似以下选项:

Shopify App
Shopify Connection
Connect to Shopify

具体名称以当前 Gadget 页面为准。

Gadget 通常可以帮助项目准备:

  • Node.js 后端
  • React 前端
  • PostgreSQL 数据库
  • Shopify OAuth 连接
  • Session Token 验证
  • Shopify API 客户端
  • Webhook 接收能力
  • Development 和 Production 环境

但不要默认“创建了 Shopify Connection,就代表所有同步和 Webhook 都已经完成”。创建后仍然需要检查连接配置、模型、权限和 Webhook 设置。


六、配置 Shopify Connection

在 Gadget 项目中找到 Shopify Connection,常见位置可能是:

Connections → Shopify

或者:

Settings → Connections → Shopify

将 Shopify 中的开发环境凭据填入 Gadget:

Client ID
Client Secret

保存前检查:

  • Client ID 没有多余空格
  • Client Secret 没有多余空格
  • 两个字段没有填反
  • Development 凭据没有填到 Production
  • 凭据属于当前 Shopify App

如果 Gadget 提供测试连接按钮,可以保存后执行连接测试。


七、只申请当前需要的权限

本教程第一版只同步商品,因此建议先申请:

read_products

如果应用还需要修改商品,再考虑:

write_products

其他常见权限包括:

功能可能需要的权限
查看商品read_products
修改商品write_products
查看订单read_orders
查看客户read_customers
查看库存read_inventory
修改库存write_inventory

不要为了方便一次申请全部权限。

权限越多:

  • 商家越难理解应用需要什么
  • 授权页面越复杂
  • 数据保护要求可能越高
  • 应用审核可能更复杂
  • 后续权限调整更麻烦

如果已经安装应用后又新增 Scope,旧安装通常需要重新授权,才能获得新增权限。


八、配置 App URL 和 OAuth 回调地址

这是最容易出错的步骤。

Shopify 需要知道两个地址:

App URL
OAuth Callback URL

从 Gadget 的 Shopify Connection、安装说明或部署页面中复制实际地址,不要根据教程示例手动猜。

可能类似:

https://your-app.gadget.app

OAuth 回调地址可能类似:

https://your-app.gadget.app/api/connections/auth/shopify/callback

然后回到 Shopify App 配置中,填写:

App URL
Allowed redirection URL

如果 Gadget 显示多个回调地址,就按照 Gadget 的要求全部添加。

重点检查:

  • 必须使用 HTTPS
  • App URL 和回调 URL 不要填反
  • 路径不能少
  • 开发地址和生产地址不能混用
  • 结尾斜杠保持一致
  • 不要复制隐藏空格
  • 当前 Client ID 必须属于当前环境

同时确认应用启用了:

Embedded App
Embed app in Shopify admin

九、安装应用到开发商店

回到 Shopify App 管理页面,找到测试或安装入口。名称可能是:

Select store
Test your app
Install app
Choose development store

选择:

cart-transform-testing

点击安装后,Shopify 会显示应用申请的权限。

确认权限后点击:

Install

整个过程大致是:

Shopify 发起 OAuth
        ↓
Gadget 验证授权请求
        ↓
商家同意权限
        ↓
Gadget 保存商店连接
        ↓
应用完成安装
        ↓
页面跳转到 Embedded App

安装后先不要急着做同步,先确认:

  • 应用能从 Shopify Admin 打开
  • 没有无限跳转
  • 没有拒绝访问错误
  • 刷新页面后仍然能打开
  • Gadget 中出现了当前商店记录

十、区分三种重要凭证

开发时经常把这些概念混在一起。

凭证用途保存位置
Client ID识别应用是谁应用配置
Client Secret证明应用身份服务端密钥
Session Token验证嵌入式页面请求身份前端请求和后端验证流程
Admin API Access Token让服务器代表商店调用 Admin API只能保存在服务端

正确的数据流应该是:

React 页面
   ↓ Session Token
Gadget 后端确认当前商店
   ↓ Access Token
Shopify Admin API

不要这样做:

React 页面
   ↓ Access Token
Shopify Admin API

Access Token 一旦放到浏览器中,就可能被用户或恶意脚本看到。


十一、执行第一次历史同步

Webhook 只能通知安装之后发生的变化。

如果商店在安装应用前已经有商品,这些商品不会因为 Webhook 自动出现。因此需要执行历史同步。

在 Gadget 中找到类似:

Shopify Connection
Shopify Shop
Syncs
Data sync
Start sync

选择:

Products
Product Variants
Product Images

然后开始同步。

同步完成后,不要只看“Completed”,还要抽查数据。

建议检查:

Shopify 商品数量
Gadget 商品数量
商品 ID
商品标题
商品状态
商品变体
商品图片
创建时间和更新时间
失败记录

随机打开 3 到 5 个商品,对比 Shopify 和 Gadget 中的数据。

要记住:

历史同步 = 补过去的数据
Webhook = 接收未来的变化

它们是两个不同系统,不能互相替代。

Gadget 是否自动处理分页、速率限制和错误重试,要以当前 Connection 和 Sync 功能实际提供的能力为准。生产环境中仍然要查看同步日志和失败记录。


十二、测试实时 Webhook

Shopify 商品相关的 Webhook topic 通常使用复数形式:

products/create
products/update
products/delete

测试商品创建

在 Shopify Admin 中进入:

Products → Add product

创建测试商品:

Title: Webhook Test T-shirt
Price: 29.99
Status: Active

保存后,检查:

  1. Shopify 商品是否创建成功
  2. Webhook 是否发送
  3. Gadget 日志是否收到通知
  4. Gadget 商品数据表是否出现记录
  5. Shopify 商品 ID 是否正确

正常链路应该是:

Shopify 创建商品
        ↓
products/create
        ↓
Gadget 接收 Webhook
        ↓
Gadget 创建或更新数据库记录

不要承诺 Webhook 一定在几秒内到达。Webhook 是异步机制,可能发生延迟或重试。

测试商品修改

将商品标题改为:

Webhook Test T-shirt Updated

保存后,查看 Gadget 中的标题是否更新。

测试商品删除

删除测试商品,再检查 Gadget 中的对应记录。

具体行为取决于模型设计,可能是:

  • 删除 Gadget 记录
  • 标记为已删除
  • 保留记录但更新状态
  • 保留同步记录但不再显示

这部分需要在应用设计中明确,不要让读者自行猜测。


十三、为 Webhook 添加后端逻辑

商品同步成功后,可以在记录创建或更新时运行自定义代码。

在 Shopify Product 模型中找到对应 Action,例如:

Create
Update
Shopify webhook action
After action
On success

日志示例:

export const run = async ({ record, logger }) => {
  logger.info(
    {
      productId: record.id,
      title: record.title,
    },
    "Received a Shopify product"
  );
};

具体参数和文件结构以 Gadget 自动生成的代码为准。

Webhook 后可以执行:

  • 自动检查商品是否有图片
  • 根据商品标题打标签
  • 将商品发送到 ERP
  • 生成 AI 商品描述
  • 根据库存发送通知
  • 调用第三方 API
  • 创建后台任务
  • 更新 Shopify 商品

必须处理重复 Webhook

Webhook 可能因为网络问题或处理失败而重试,因此不能假设一个事件只会到达一次。

推荐使用 Shopify 资源 ID 作为稳定标识:

收到商品 Webhook
        ↓
查找 Shopify product ID
        ↓
已经存在则更新
        ↓
不存在才创建

还要防止这种循环:

Shopify 修改商品
        ↓
Webhook 到达 Gadget
        ↓
Gadget 又修改 Shopify
        ↓
Shopify 再次发送 Webhook

解决办法包括:

  • 写入前判断字段是否真的发生变化
  • 保存自动处理标记
  • 使用幂等逻辑
  • 不要每次 Webhook 都无条件写回 Shopify
  • 将耗时任务放入后台队列

十四、开发 React 嵌入式页面

Gadget 项目通常带有 React 前端,可以做一个简单的商品同步面板。

第一版页面可以包含:

  • 当前商店名称
  • 商品总数
  • 最近同步时间
  • 手动同步按钮
  • 商品标题列表
  • 商品状态
  • 错误提示
  • Loading 状态

推荐的数据流:

React 页面
   ↓
Gadget API
   ↓
Gadget 数据库或后端 Action
   ↓
Shopify Admin API

不要让 React 直接携带 Shopify Access Token 请求 Shopify。

前端应该只负责:

  • 显示数据
  • 提交用户操作
  • 显示加载状态
  • 显示错误信息

真正访问 Shopify 的动作应该由 Gadget 后端完成。


十五、部署前测试清单

安装

  • 开发商店可以打开安装流程
  • OAuth 可以完成
  • 权限显示正确
  • 应用显示在 Shopify Admin
  • 刷新页面不会重复安装
  • 应用不会无限跳转

数据同步

  • 历史商品可以同步
  • 商品变体可以同步
  • 商品图片可以同步
  • 同步失败时能看到错误
  • 大量数据同步不会静默失败
  • 同步可以重试

Webhook

  • 新建商品能创建记录
  • 修改商品能更新记录
  • 删除商品按预期处理
  • 重复 Webhook 不会产生重复数据
  • 失败 Webhook 会记录日志
  • 后端逻辑具备幂等性

安全

  • Access Token 不出现在前端
  • Client Secret 不提交到 GitHub
  • 日志中不打印完整密钥
  • 只申请真正需要的 Scope
  • 新增权限后可以重新授权
  • 卸载应用后旧连接不能继续使用

前端

  • Shopify Admin 中可以打开
  • 页面刷新正常
  • Loading 状态清晰
  • 空数据状态清晰
  • 错误信息可以理解
  • 窄屏下页面基本可用

十六、准备生产环境

Development 和 Production 应该隔离。

如果 Gadget 的两个环境需要独立的:

  • Client ID
  • Client Secret
  • App URL
  • OAuth 回调地址
  • 数据库
  • 环境变量

那么建议创建独立的生产应用:

Product Sync Manager - Production

获取新的:

Production Client ID
Production Client Secret

开发和生产凭据不要混用。

需要注意,创建独立生产 App 是一种隔离方案,不一定是所有项目的强制要求。最终要根据 Shopify App 版本管理和 Gadget 的环境管理方式决定。


十七、配置生产应用

切换 Gadget 到 Production 配置,填写生产凭据。

然后从 Gadget 获取:

Production App URL
Production OAuth Callback URL

回到 Shopify 生产应用中填写:

App URL
Allowed redirection URL

再次检查:

  • 使用 HTTPS
  • 没有使用开发 URL
  • 回调路径完整
  • Client ID 和 Client Secret 属于生产应用
  • 生产应用权限和 Gadget 功能匹配
  • Embedded App 配置正确
  • 生产环境变量已经设置

开发数据库和生产数据库通常是分开的,因此开发环境中的测试商品不会自动进入生产环境。

生产安装完成后,需要重新执行:

生产安装
→ 创建 Shop 记录
→ 首次历史同步
→ 测试生产 Webhook

十八、部署到 Gadget Production

在 Gadget 中执行类似:

Deploy to Production

具体按钮名称以当前项目为准。

部署后检查:

  • 前端是否可以打开
  • 后端是否启动成功
  • 数据库迁移是否成功
  • 环境变量是否齐全
  • Shopify 生产凭据是否正确
  • 生产日志是否有报错
  • 生产回调地址是否生效

不要只确认“生产页面能访问”,还要真正执行一次:

  1. 安装生产应用
  2. 同步历史商品
  3. 创建一个测试商品
  4. 修改商品标题
  5. 删除测试商品
  6. 检查 Gadget 数据和日志

十九、选择应用分发方式

Custom Distribution

适合:

  • 单个商家定制
  • 企业内部工具
  • 特定客户项目
  • 特定组织中的商店

Custom App 不能使用 Shopify Billing API 向商家收费。

Public Distribution

适合:

  • 多个独立商家
  • SaaS 应用
  • 准备提交 Shopify App Store 的应用

公开应用通常需要准备:

  • 应用介绍
  • 隐私政策
  • 服务条款
  • 技术支持页面
  • 应用截图和图标
  • 定价信息
  • 数据删除机制
  • 审核资料

不要把“生成安装链接”和“应用已经可以公开销售”混为一谈。

如果目标是面向多个独立商家销售,应该一开始就按照 Public App 的要求规划权限、隐私、收费和审核流程。


二十、常见问题排查

OAuth 回调地址不匹配

常见错误:

redirect_uri is not whitelisted

检查:

  • Shopify 配置和 Gadget 地址是否完全一致
  • 是否少了路径
  • 是否误用了开发地址
  • 是否使用 HTTPS
  • 结尾斜杠是否不同
  • 当前 Client ID 是否对应当前环境

安装后无限跳转

可能原因:

  • App URL 错误
  • Session Token 验证失败
  • 开发和生产凭据混用
  • Embedded App 配置错误
  • 当前商店没有完成安装
  • Cookie 或浏览器缓存异常

排查方式:

  1. 清除站点 Cookie
  2. 从 Shopify Admin 的 Apps 区域重新打开
  3. 查看 Gadget 后端日志
  4. 检查当前环境
  5. 确认 Client ID 和 App URL 属于同一个应用

商品没有同步

依次检查:

  • 是否启用了 Product 模型
  • 是否申请了 read_products
  • 商家是否同意了最新权限
  • 是否运行过历史同步
  • Webhook 是否成功配置
  • Gadget 日志是否有错误
  • 查看的是 Development 还是 Production
  • 商品是否属于当前测试商店

修改权限后仍然不能使用

新增 Scope 后,旧安装通常不会自动获得权限。

可以尝试:

  1. 更新 Shopify App 权限
  2. 更新 Gadget Connection
  3. 创建或发布新的应用版本
  4. 重新部署
  5. 让商家重新授权
  6. 必要时卸载并重新安装

Webhook 重复执行

不要假设 Webhook 只发送一次。

使用 Shopify 资源 ID作为唯一业务标识,写入前先判断记录是否已经存在。

开发环境正常,生产环境失败

重点检查:

  • Production Client ID
  • Production Client Secret
  • Production App URL
  • Production OAuth Callback URL
  • 生产环境变量
  • 数据库迁移
  • 生产 Scopes
  • 应用分发状态
  • 是否误用了开发安装链接

二十一、最终操作顺序

建议按照这个顺序执行:

  1. 注册 Shopify Partners 或开发者账号
  2. 创建带测试数据的开发商店
  3. 创建 Shopify 开发应用
  4. 获取开发 Client ID 和 Client Secret
  5. 创建 Gadget Shopify 项目
  6. 配置 Development Shopify Connection
  7. 申请最小 API 权限
  8. 从 Gadget 复制开发 App URL 和回调地址
  9. 将 URL 填回 Shopify App 配置
  10. 启用 Embedded App
  11. 安装到开发商店
  12. 确认 Gadget 出现 Shop 记录
  13. 执行历史商品同步
  14. 测试 products/create
  15. 测试 products/update
  16. 测试 products/delete
  17. 增加后端业务逻辑
  18. 开发 React 管理页面
  19. 测试重复 Webhook 和失败重试
  20. 创建或配置生产应用
  21. 设置生产 Client ID 和 Client Secret
  22. 配置生产 URL 和回调地址
  23. 部署 Gadget Production
  24. 安装生产版本
  25. 执行首次生产同步
  26. 测试生产 Webhook
  27. 持续查看日志和同步状态

结语:记住这四件事

1. 历史同步和 Webhook 是两套机制

历史同步负责过去
Webhook 负责未来

2. Session Token 和 Access Token 不是同一个东西

Session Token 用于验证当前页面请求,Access Token 用于服务端访问 Shopify Admin API。

3. Custom App 和 Public App 的收费方式不同

Custom Distribution 适合特定客户,不能直接使用 Shopify Billing API。面向多个独立商家收费时,应规划 Public App。

4. 开发环境成功不代表生产环境成功

生产环境必须重新检查:

凭据
URL
权限
数据库
Webhook
同步
分发方式

完成这些步骤后,你就不只是“创建了一个 Gadget 项目”,而是真正完成了一条可验证的 Shopify App 开发链路:

Shopify
→ OAuth
→ Gadget
→ PostgreSQL
→ Admin API
→ Webhook
→ React
→ Production

这条链路跑通之后,再继续增加订单同步、库存同步、ERP 对接、AI 商品处理或自动化任务,会稳很多。