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"
}
]
}
]
}
}
}
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_CREATE、PRODUCTS_UPDATE、CUSTOMERS_CREATE、INVENTORY_LEVELS_UPDATE 等数十种。
GraphQL Explorer
Shopify 提供了一个交互式 GraphQL 浏览器用于测试查询:
- 进入你的 合作伙伴仪表板
- 选择一个应用,然后点击 API access
- 点击 GraphiQL 打开浏览器
或者使用 Shopify CLI:
# Open GraphiQL for your dev store
shopify app dev --graphiql
浏览器提供:
- Schema 文档:浏览所有类型、字段和参数
- 自动补全:输入即可获得建议
- 查询验证:执行前高亮显示错误
- 变量编辑器:使用不同输入进行测试
- 响应查看器:格式化的 JSON 输出
与其在 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
}
}
当 status 为 COMPLETED 时,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 模板语言。