Skip to main content

Shopify GraphQL 基础

GraphQL 是与 Shopify API 通信的主要语言。如果你之前只使用过 REST API,GraphQL 会有所不同——你精确描述所需的数据,服务器就会返回精确匹配的数据结构。无需过度获取、无需不足获取、无需串联多个请求。本课从零开始教你 GraphQL,包含你每天都会用到的 Shopify 特定模式。

为什么选择 GraphQL 而非 REST

考虑获取一个产品及其变体、图片和 metafield 的场景。使用 REST,你可能需要:

GET /admin/api/2026-01/products/123.json          → product data
GET /admin/api/2026-01/products/123/variants.json → variant data
GET /admin/api/2026-01/products/123/images.json → image data
GET /admin/api/2026-01/products/123/metafields.json → metafield data

那是四个 HTTP 请求,每个都返回你可能不需要的字段。而使用 GraphQL:

query {
product(id: "gid://shopify/Product/123") {
title
status
variants(first: 10) {
edges {
node {
title
price
inventoryQuantity
}
}
}
images(first: 5) {
edges {
node {
url
altText
}
}
}
metafields(first: 10) {
edges {
node {
namespace
key
value
}
}
}
}
}

一个请求。精确获取你需要的字段。这就是 Shopify 全力投入 GraphQL 的原因。

查询:读取数据

查询是你从 Shopify 读取数据的方式。每个查询都从一个根字段开始,然后深入数据图。

基本查询结构

query ProductList {
products(first: 10, query: "status:active") {
edges {
node {
id
title
handle
status
totalInventory
priceRangeV2 {
minVariantPrice {
amount
currencyCode
}
maxVariantPrice {
amount
currencyCode
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

关键概念:

  • 操作名称ProductList):可选但推荐——有助于调试和日志记录
  • 参数first: 10, query: "status:active"):过滤和分页结果
  • 选择集:你想要返回的嵌套字段
  • 边和节点:Shopify 对列表使用 Relay 连接模式
  • pageInfo:基于游标分页的分页元数据

使用变量

永远不要直接将值插入查询字符串中。使用 变量 代替:

query ProductById($id: ID!) {
product(id: $id) {
title
description
vendor
productType
tags
createdAt
}
}
{
"variables": {
"id": "gid://shopify/Product/7654321"
}
}
始终使用变量

变量可以防止 GraphQL 注入攻击、启用查询缓存,并使你的代码更简洁。Remix 模板中的 Shopify Admin GraphQL 客户端原生支持变量。

常见查询模式

获取带有行项和履行状态的订单:

query RecentOrders($first: Int!) {
orders(first: $first, sortKey: CREATED_AT, reverse: true) {
edges {
node {
id
name
displayFinancialStatus
displayFulfillmentStatus
totalPriceSet {
shopMoney {
amount
currencyCode
}
}
lineItems(first: 50) {
edges {
node {
title
quantity
variant {
sku
}
}
}
}
customer {
displayName
email
}
}
}
}
}

使用过滤器搜索客户:

query SearchCustomers($query: String!) {
customers(first: 25, query: $query) {
edges {
node {
id
displayName
email
ordersCount
totalSpent
tags
addresses {
city
province
country
}
}
}
}
}

检查各仓库的库存水平:

query InventoryLevels($variantId: ID!) {
productVariant(id: $variantId) {
title
sku
inventoryItem {
inventoryLevels(first: 10) {
edges {
node {
location {
name
}
quantities(names: ["available", "committed", "on_hand"]) {
name
quantity
}
}
}
}
}
}
}

变更:写入数据

变更用于修改数据。它们在 Shopify API 中遵循一致的模式:你传递一个 input 对象,变更返回修改后的资源以及所有用户错误。

创建产品

mutation CreateProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
title
handle
status
variants(first: 5) {
edges {
node {
id
price
}
}
}
}
userErrors {
field
message
}
}
}
{
"variables": {
"input": {
"title": "Premium Widget",
"descriptionHtml": "<p>A high-quality widget for discerning customers.</p>",
"vendor": "WidgetCo",
"productType": "Widgets",
"tags": ["premium", "new-arrival"],
"status": "DRAFT",
"variants": [
{
"price": "29.99",
"sku": "WIDGET-001",
"inventoryQuantities": [
{
"availableQuantity": 100,
"locationId": "gid://shopify/Location/1"
}
]
}
]
}
}
}
始终检查 userErrors

Shopify 的变更返回 userErrors 数组而不是抛出异常。一个变更可以返回 HTTP 200 和成功的 GraphQL 响应,但仍然包含 userErrors。在假定操作成功之前,始终检查此数组。

更新订单标签

mutation AddOrderTags($id: ID!, $tags: [String!]!) {
tagsAdd(id: $id, tags: $tags) {
node {
... on Order {
id
tags
}
}
userErrors {
field
message
}
}
}

Metafield 变更

mutation SetMetafields($metafields: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafields) {
metafields {
id
namespace
key
value
}
userErrors {
field
message
}
}
}
{
"variables": {
"metafields": [
{
"ownerId": "gid://shopify/Product/123",
"namespace": "custom",
"key": "warranty_years",
"value": "3",
"type": "number_integer"
}
]
}
}

订阅:实时更新

GraphQL 订阅让你的应用通过 Webhook 接收实时更新。虽然 Shopify 不支持基于 WebSocket 的订阅,但它使用通过 GraphQL 注册的 Webhook 订阅

mutation CreateWebhookSubscription {
webhookSubscriptionCreate(
topic: ORDERS_CREATE
webhookSubscription: {
callbackUrl: "https://your-app.com/webhooks/orders-create"
format: JSON
}
) {
webhookSubscription {
id
topic
endpoint {
... on WebhookHttpEndpoint {
callbackUrl
}
}
}
userErrors {
field
message
}
}
}

可用的主题包括 ORDERS_CREATEPRODUCTS_UPDATECUSTOMERS_CREATEINVENTORY_LEVELS_UPDATE 等数十种。

GraphQL Explorer

Shopify 提供了一个交互式 GraphQL 浏览器用于测试查询:

  1. 进入你的 合作伙伴仪表板
  2. 选择一个应用,然后点击 API access
  3. 点击 GraphiQL 打开浏览器

或者使用 Shopify CLI:

# Open GraphiQL for your dev store
shopify app dev --graphiql

浏览器提供:

  • Schema 文档:浏览所有类型、字段和参数
  • 自动补全:输入即可获得建议
  • 查询验证:执行前高亮显示错误
  • 变量编辑器:使用不同输入进行测试
  • 响应查看器:格式化的 JSON 输出
使用 Claude Code 作为你的 GraphQL Explorer

与其在 GraphiQL 中手动编写查询,不如向 Claude Code 提问:"编写一个 GraphQL 查询来获取最近 5 个订单及其行项、客户邮箱和履行状态。" Claude Code 理解 Shopify 的 Schema,会生成正确、高效的查询。

批量操作

当你需要处理数千或数百万条记录时,逐个查询太慢了。Shopify 的 Bulk Operations API 让你可以异步地对整个数据集运行查询。

mutation BulkExportProducts {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
handle
status
variants {
edges {
node {
id
sku
price
inventoryQuantity
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
url
}
userErrors {
field
message
}
}
}

批量操作是异步运行的。轮询以检查完成状态:

query BulkOperationStatus {
currentBulkOperation {
id
status
objectCount
url
errorCode
fileSize
}
}

statusCOMPLETED 时,url 字段包含一个指向 JSONL 文件的链接,其中包含所有结果。每行是一个 JSON 对象,嵌套对象通过 __parentId 字段引用其父级。

{"id":"gid://shopify/Product/1","title":"Widget A","handle":"widget-a","status":"ACTIVE"}
{"id":"gid://shopify/ProductVariant/10","sku":"WA-001","price":"29.99","__parentId":"gid://shopify/Product/1"}
{"id":"gid://shopify/Product/2","title":"Widget B","handle":"widget-b","status":"DRAFT"}
{"id":"gid://shopify/ProductVariant/20","sku":"WB-001","price":"19.99","__parentId":"gid://shopify/Product/2"}
何时使用批量操作

当你需要导出或处理超过几百条记录时使用批量操作。常见用例:数据迁移、报告、与外部系统同步以及初始数据加载。批量操作不受正常速率限制的约束。

错误处理

Shopify 中的 GraphQL 错误有两种形式:

1. GraphQL 错误(查询级别)

这些表明查询本身存在问题——语法错误、无效字段、认证失败:

{
"errors": [
{
"message": "Field 'nonExistentField' doesn't exist on type 'Product'",
"locations": [{ "line": 3, "column": 5 }]
}
]
}

2. 用户错误(业务逻辑)

这些表明有效的查询未通过业务规则验证:

{
"data": {
"productCreate": {
"product": null,
"userErrors": [
{
"field": ["input", "title"],
"message": "Title can't be blank"
}
]
}
}
}

始终处理这两种类型:

const response = await admin.graphql(query, { variables });
const { data, errors } = await response.json();

// Check for query-level errors
if (errors) {
console.error("GraphQL errors:", errors);
throw new Error(errors[0].message);
}

// Check for business logic errors
const result = data.productCreate;
if (result.userErrors.length > 0) {
console.error("User errors:", result.userErrors);
throw new Error(result.userErrors[0].message);
}

// Success
return result.product;

核心要点

  • GraphQL 让你在单个请求中精确获取所需数据
  • 使用 变量 而不是字符串插值以提高安全性和缓存性能
  • 在变更响应中始终检查 userErrors
  • 对大型数据集(数百条记录或更多)使用 批量操作
  • Relay 连接模式(edges/nodes/pageInfo)用于所有列表
  • Claude Code 可以从自然语言描述生成 Shopify GraphQL 查询

接下来,我们将探索 Liquid——驱动 Online Store 2.0 主题的 Shopify 模板语言。