Skip to main content

Shopify GraphQL 基礎

GraphQL 是與 Shopify API 溝通的主要語言。如果您之前只使用過 REST API,GraphQL 會感覺不同——您描述所需的確切資料,伺服器就精確回傳該結構。不會過度擷取,不會不足擷取,不需要串連多個請求。本課程從零開始教您 GraphQL,並提供每天都會用到的 Shopify 特定模式。

為什麼選擇 GraphQL 而非 REST

考慮擷取一個商品及其款式、圖片和中繼欄位。使用 REST,您可能需要:

GET /admin/api/2026-01/products/123.json          → 商品資料
GET /admin/api/2026-01/products/123/variants.json → 款式資料
GET /admin/api/2026-01/products/123/images.json → 圖片資料
GET /admin/api/2026-01/products/123/metafields.json → 中繼欄位資料

那是四個 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
}
}
}

中繼欄位變更操作

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 探索器

Shopify 提供了互動式 GraphQL 探索器用於測試查詢:

  1. 前往您的合作夥伴儀表板
  2. 選擇一個應用程式,然後選擇 API 存取
  3. 點擊 GraphiQL 開啟探索器

或使用 Shopify CLI:

# 為您的開發商店開啟 GraphiQL
shopify app dev --graphiql

探索器提供:

  • 結構文件: 瀏覽所有類型、欄位和引數
  • 自動完成: 輸入即獲得建議
  • 查詢驗證: 執行前高亮顯示錯誤
  • 變數編輯器: 使用不同輸入進行測試
  • 回應檢視器: 格式化的 JSON 輸出
使用 Claude Code 作為您的 GraphQL 探索器

與其在 GraphiQL 中手動撰寫查詢,不如問 Claude Code:「撰寫一個 GraphQL 查詢來擷取最近 5 筆訂單及其明細、客戶電子郵件和出貨狀態。」Claude Code 理解 Shopify 的結構,會生成正確、高效的查詢。

批次操作

當您需要處理數千或數百萬筆記錄時,個別查詢太慢了。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();

// 檢查查詢層級錯誤
if (errors) {
console.error("GraphQL errors:", errors);
throw new Error(errors[0].message);
}

// 檢查商業邏輯錯誤
const result = data.productCreate;
if (result.userErrors.length > 0) {
console.error("User errors:", result.userErrors);
throw new Error(result.userErrors[0].message);
}

// 成功
return result.product;

重點摘要

  • GraphQL 讓您在單一請求中精確擷取所需資料
  • 使用變數而非字串內插,以確保安全性和快取
  • 在變更操作回應中始終檢查 userErrors
  • 對大型資料集(數百筆記錄以上)使用批次操作
  • Relay 連接模式(edges/nodes/pageInfo)用於所有列表
  • Claude Code 可以從自然語言描述生成 Shopify GraphQL 查詢

接下來,我們將探索 Liquid——驅動 Online Store 2.0 佈景主題的 Shopify 模板語言。