2024年2月6日

Shopify API でデータ連携 (GraphQL API 編)

前々回では「Shopifyとは何なのか?」「メリット・デメリットは?」「できること・できないことは?」など、Shopifyの概要をお話しして、前回はもう少し技術的なところに踏み込んで「基幹システムとの連携」を観点に、ShopifyAPIについて説明しました。

今回も引き続きAPIについてのお話なのですが、前回のREST APIとはまた少し違うGraphQL APIを紹介します。

 

ShopifyGraphQL APIとは?

Graph QL とは、Shopifyのデータをクエリで取得できるAPIです。

Shopifyから商品情報、注文情報、顧客情報など、どのようなデータを取得・更新できるのかについては前回のREST APIでも触れましたが、GraphQL APIREST APIよりも少ないリクエスト回数で、必要なデータを取得することができます。

 

Shopify GraphQL APIの公式ドキュメント:

https://shopify.dev/docs/api/admin-graphql

 

REST APIと比べると普及率はまだまだ低いので、そもそもGraphQLとは何なのかを説明します。

GraphQLはAPIの新しいプロトコルで、データベースからデータを取得するためのクエリ言語です。

REST APIとは異なり、必要なデータ項目だけを指定して取得できます。

 

これを踏まえてShopify REST APIShopify GraphQL APIとの違いを以下に挙げます。

 

Shopify GraphQL APIの概要

クエリを1つ書けばさまざまなデータを取得・更新できるので、REST APIのように「注文情報はOrdersAPIを呼び出して、発送情報はProductsAPIを呼び出して、……」と、データごとに呼び出すAPIを分ける必要はありません。

 

Shopify GraphQL APIのエンドポイントは以下の形式なのですが、

 

https://{SHOPIFY_DOMAIN}/admin/api/2022-02/graphql.json

({SHOPIFY_DOMAIN}は、Shopifyストアのドメイン名)

 

REST APIと違って「2022-02/」の後ろに「Orders」や「Customers」などをくっ付けて、呼び出すAPIの指定は不要です。この固定のエンドポイント1つだけで事足ります。

(ただし、2022-02 APIのバージョンなので、2023-07 2023-10 にどんどん変わっていきます)

そして、使用するHTTPメソッドも以下の1つだけです。

 

  • POST : クエリ (データの取得/作成/更新/削除) を送信する

 

エンドポイントも1つ、HTTPメソッドも1つ、ではどうやって「どのデータを取得するのか」「データをどうする(取得/更新する)のか」を指定するのでしょうか。

ここで、先ほどから触れている「クエリ」の登場です。

リクエストボディに「このデータをこうしたい」とクエリを書いてGraphQL APIを呼び出すわけです。

もちろん、クエリにはデータの条件なども書けるので「今日入った注文を全件取得」、「注文番号999の支払い情報だけ取得」などといった操作も可能です。

 

セキュリティ面にも言及しておきますと、APIキー、ロールベースのアクセス制御、暗号化(SSL)などはShopify REST APIと同様ですので前回の記事をご参照下さい。

 

 

Shopify GraphQL APIの使い方

では、実際にAPIを実行してみましょう。

 

クエリ送信のURLは以下の通りです。

https://storedomain.myshopify.com/admin/api/2023-07/graphql.json

 

以下の条件で発送データを取得するクエリをリクエストボディに書きます。

  • 数回に分割して発送された注文番号「5328720593121」の、全ての発送情報を取得する
  • 送り状の情報(trackingInfo)、発送された商品の情報(fulfillmentLineItems)、発送ステータス(status)などを取得する

 

クエリ:

{
  order(id: "gid://shopify/Order/5328720593121")
  {
    fulfillmentOrders(first: 5, reverse:true)
    {
      edges {
        node {
          id
          status
          fulfillAt
          fulfillments(first: 1)
          {
            edges {
                node {
                  trackingInfo {
                    company
                    number
                  }
                  fulfillmentLineItems(first: 10)
                  {
                    edges {
                      node {
                        quantity
                        lineItem {
                        title
                        quantity
                        originalUnitPriceSet {
                            shopMoney {
                                amount
                                currencyCode
                            }
                        }
                        taxLines(first: 5) {
                            rate
                        }
                        discountAllocations {
                            allocatedAmount {
                                amount
                                currencyCode
                            }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

 

リクエストヘッダにAPIキーを設定し、リクエストをPOST送信すると、JSON形式で以下のようなレスポンスが返ってきます。

 

{
  "data": {
    "order": {
      "fulfillmentOrders": {
        "edges": [
          {
            "node": {
              "id": "gid:\/\/shopify\/FulfillmentOrder\/6386604474593",
              "status": "CLOSED",
              "fulfillAt": "2023-10-02T04:00:00Z",
              "fulfillments": {
                "edges": [
                  {
                    "node": {
                      "trackingInfo": [
                        {
                          "company": "Fedex",
                          "number": "1231275"
                        }
                      ],
                      "fulfillmentLineItems": {
                        "edges": [
                          {
                            "node": {
                              "quantity": 1,
                              "lineItem": {
                                "title": "アロマオイル (ピーチ)",
                                "quantity": 1,
                                "originalUnitPriceSet": {
                                  "shopMoney": {
                                    "amount": "1100.0",
                                    "currencyCode": "JPY"
                                  }
                                },
                                "taxLines": [
                                  {
                                    "rate": 0.1
                                  }
                                ],
                                "discountAllocations": []
                              }
                            }
                          },
                          {
                            "node": {
                              "quantity": 1,
                              "lineItem": {
                                "title": "アロマオイル (バニラ)",
                                "quantity": 1,
                                "originalUnitPriceSet": {
                                  "shopMoney": {
                                    "amount": "1000.0",
                                    "currencyCode": "JPY"
                                  }
                                },
                                "taxLines": [
                                  {
                                    "rate": 0.1
                                  }
                                ],
                                "discountAllocations": []
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              }
            }
          },
          {
            "node": {
              "id": "gid:\/\/shopify\/FulfillmentOrder\/6382008107233",
              "status": "CLOSED",
              "fulfillAt": "2023-09-27T10:00:00Z",
              "fulfillments": {
                "edges": [
                  {
                    "node": {
                      "trackingInfo": [
                        {
                          "company": "Fedex",
                          "number": "1231273"
                        }
                      ],
                      "fulfillmentLineItems": {
                        "edges": [
                          {
                            "node": {
                              "quantity": 1,
                              "lineItem": {
                                "title": "マイクロファイバー バスタオル",
                                "quantity": 1,
                                "originalUnitPriceSet": {
                                  "shopMoney": {
                                    "amount": "1200.0",
                                    "currencyCode": "JPY"
                                  }
                                },
                                "taxLines": [
                                  {
                                    "rate": 0.1
                                  }
                                ],
                                "discountAllocations": []
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              }
            }
          },
          {
            "node": {
              "id": "gid:\/\/shopify\/FulfillmentOrder\/6382007091425",
              "status": "CLOSED",
              "fulfillAt": "2023-09-27T10:00:00Z",
              "fulfillments": {
                "edges": []
              }
            }
          }
        ]
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 288,
      "actualQueryCost": 35,
      "throttleStatus": {
        "maximumAvailable": 1000.0,
        "currentlyAvailable": 965,
        "restoreRate": 50.0
      }
    }
  }
}

 

クエリで指定した通りの項目のみ、きちんと返ってきています。

ただ、末尾の項目「extensions」はクエリで指定しなくても必ず付いてきます。

これはクエリ実行にかかったコストの情報です。コストは、クエリの複雑さや取得するデータ量によって変わってくるのですが、この値が大きくなるとエラーが発生します。

 

コストエラーが発生した時はどうなるのか見てみましょう。

先ほどのクエリにて「first: 5」や「first: 10」を指定しましたが、これは「1つの注文で5回超の分割発送なんてないだろう」「1回の発送に10商品超の梱包なんてないだろう」という業務仕様から決めた値なのですが、この数値を大きくすると、以下のレスポンスが返ってきました。

 

{
  "errors": [
    {
      "message": "Query cost is 2853, which exceeds the single query max cost limit (1000).\n\nSee https://shopify.dev/concepts/about-apis/rate-limits for more information on how the\ncost of a query is calculated.\n\nTo query larger amounts of data with fewer limits, bulk operations should be used instead.\nSee https://shopify.dev/api/usage/bulk-operations/queries for usage details.\n",
      "extensions": {
        "code": "MAX_COST_EXCEEDED",
        "cost": 2853,
        "maxCost": 1000,
        "documentation": "https://shopify.dev/api/usage/rate-limits"
      }
    }
  ]
}

 

REST APIと違って、このようなエラーが発生してもHTTPステータスコードは200(成功)です。

ステータスコードではなく、エラーメッセージを確認しないとエラー検出ができないので要注意です。

 

 

Shopify GraphQL APIを使った実例

Shopify REST APIでできることと、ほとんど同じなのですが比較しつつ実例をご紹介します。

 

  • 管理画面上のタイムラインのデータを取得する

 

商品を発送した、支払い金額の一部を返金した、など注文に対してどんな動きがあったかを把握できます。

タイムラインのデータはGraphQL APIでしか取得できません。

 

このように、REST APIでは取得できないデータが他にも結構あることを知り、私はGraphQL推しになりました。Shopifyサイドも今後はGraphQL APIのアップデートに力を入れていくのではないでしょうか。

弊社で携わったプロジェクトでもREST APIからGraphQL APIへ移行していきましょう、という動きがありました。

 

そこで、当該プロジェクトでも積極的にGraphQLを実装に採用したものの、支払い金額関連のデータでGraphQL API では取得できないデータ項目があることに気付きました。

そんな時は、そのデータ項目のみREST API で取得するなどしてGraphQL APIREST APIの併用で解決しましょう。

個人的には、せっかくGraphQL推しになったのに……と実に無念でしたが。

 

GraphQL に慣れないうちはクエリを書くのが難しいと感じてしまいますが、ShopifyにはGraphQLエディタが用意されています。

Shopify Admin API GraphiQL explorer

https://shopify.dev/docs/apps/tools/graphiql-admin-api

 

これを使ってクエリを作成すれば、どんなデータ項目があるのか候補を表示してくれますし、もちろんクエリの実行もできてエラーも検出してくれます。

クエリを書いているうちに、

  • このデータ項目を取得するにはこのスキーマへのコネクションを使えばいいのか〜 (=データベースのテーブル結合のようなもの)
  • このスキーマを実装してるからあのスキーマと類似してるんだな〜 (JavaC#のインターフェースをimplementsするようなもの)

という理解が深まり、REST API Shopifyに入門した頃、湧き上がった疑問「どんなデータ構造になっているんだ……。」が解明されていきました。

GraphQLから入った方が分かりやすかったかもしれない……。

 

 

■まとめ

ShopifyのGraphQL APIは、Shopifyのデータを効率的に取得するためのAPIです。

Shopify REST APIよりも少ないリクエスト回数で、必要なデータを取得することができます。

もちろん、REST API でも大抵のことはできるのですが、どうせならShopify GraphQL APIをメインで使用して、Shopifyのデータをフル活用してみてはいかがでしょうか。

とは言え、GraphQL APIREST APIよりも複雑なため、使いこなすにはある程度の知識が必要です。

Shopify GraphQL APIの公式ドキュメントを参照したり、ShopifyGraphQL エディタを使って徐々に慣れていきましょう。

 

以上、3回にわたってShopifyに関する記事をお届けしました。

弊社が担当したShopifyの案件では日本とベトナムで開発作業を分担し、ベトナム側ではまずShopify APIの項目を根気よく調査、時にはREST APIを使うべきかGraphQLを使うべきかを考察、次にコーディング、そして結合テストでは画面操作に伴うデータの変化を検証しました。
今後、Shopify関連のオフショア開発案件でそのノウハウを余すことなく活かし、日本とベトナムの両側からお力添え致しますのでShopifyの店舗開設・移行をご検討でしたら是非ご依頼下さい! Xin cảm ơn!!

 

 

記事: A.K

ShopifyによるECサイト構築支援の詳細はこちら