Shopify Storefront API の基本を理解する

Shopify 公式ヘッドレスコマースフレームワーク Hydrogen の登場により、Storefront API の役割が大きくなりました。本記事では Storefront API の基本を調査・解説していきたいと思います。

## Storefront API とは

Storefront APIは、 Web サイト、スマホアプリ、ビデオゲームなどでの購入体験を開発するために用います。既存のオンラインショップや POS では満たせない顧客体験を実現する際に利用します。顧客が商品やコレクションを閲覧し、商品をカートに追加し、チェックアウトすることを可能にする機能を提供します。

以下のユースケースで利用出来ます。

- Shopify サイトでは表現しきれないリッチな体験や他サービス・業務との連携
- Shopify 以外の Web サイト（自社メディア）でショップの商品を販売する
- スマホアプリでショップの商品を販売する
- Unity で開発したビデオゲーム上でショップの商品を販売する


## Storefront API の概要

Shopify の API 郡は大きく分けると管理者のための Admin API とエンドユーザーのための Storefront API になります。

Admin API は GraphQL と REST API があります。[Admin API のアクセストークンの取得方法はこちらの記事](https://qiita.com/t-kurasawa/items/e8c15e33ae9055146206)で解説しています。

Storefront API は GraphQL で提供されています。REST API はありません。API リクエストするための [JavaScript, Node.js, iOS, Android など公式の SDK](https://shopify.dev/api/storefront#development_frameworks_and_sdks)  や React ベースのヘッドレスコマースサイトを構築するためのフレームワーク Hydrogen があります。以下にて解説していますのでご覧ください。

https://qiita.com/t-kurasawa/items/b5f80f951fa574b17276


以降 npm ライブラリ（[@shopify/shopify-api](https://www.npmjs.com/package/@shopify/shopify-api)) と Hydrogen のサンプルを記載します。

### データ構造
Storefront API で利用できる代表的なデータ構造は以下です。

- [カート（Cart）](https://shopify.dev/api/storefront/2022-01/objects/Cart)
- [チェックアウト（Checkouts）](https://shopify.dev/api/storefront/2022-01/objects/Checkout)
- [共通（Common objects）](https://shopify.dev/api/storefront/2022-01/objects/ApiVersion)
- [お客様（Customers）](https://shopify.dev/api/storefront/2022-01/objects/Customer)
- [ストア（Online Store）](https://shopify.dev/api/storefront/2022-01/objects/Shop)
- [注文（Orders）](https://shopify.dev/api/storefront/2022-01/objects/Order)
- [商品（Products）](https://shopify.dev/api/storefront/2022-01/objects/Product)

以下、主要なデータ構造を記載します。これらはメタフィールドの設定も可能です。

#### お客様（Customers）

<details>
<summary>
Customer <br/>
お客様は、カートを操作している購入者の情報の項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/50e90e06-2c90-f76a-8bdb-d96ae6d40157.png)
（出典）[Checkout v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Customer#connections) を元に加工

</details>

<details>
<summary>
├　CartBuyerIdentity <br/>
カートを操作している購入者の情報は、カートの項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/ae46b6e6-d5c3-a071-b42d-89de388bd8f4.png)

（出典）[CartBuyerIdentity v2022-01](https://shopify.dev/api/storefront/2022-01/objects/CartBuyerIdentity#fields) を元に加工

</details>

<details>
<summary>
　　├　Cart <br/>
カートに参照元はありません。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/c09f7c13-a3e0-c38c-9fbe-b9b3de455a04.png)

（出典）[Cart v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Cart#connections) を元に加工

</details>



#### 注文（Orders）

<details>
<summary>
Order <br/>
注文は、チェックアウトの項目です。お客様と紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/2c8c71de-1cf5-a6bd-6ebe-ba08097ba162.png)

（出典）[Order v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Order#connections) を元に加工

</details>

<details>
<summary>
├　Checkout <br/>
チェックアウトは、支払いの項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/30774912-1a1c-469d-df62-09532ff76ffb.png)
（出典）[Checkout v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Checkout#connections) を元に加工

</details>

<details>
<summary>
　　├　Payment <br/>
支払いに参照元はありません。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/2cec0d0c-3d2f-d262-2782-2384a7e25aed.png)

（出典）[Payment v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Payment#fields) を元に加工

</details>

<details>
<summary>
⇔　Customer <br/>
お客様は、カートを操作している購入者の情報の項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/50e90e06-2c90-f76a-8bdb-d96ae6d40157.png)
（出典）[Checkout v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Customer#connections) を元に加工

</details>

<details>
<summary>
　　├　CartBuyerIdentity <br/>
カートを操作している購入者の情報は、カートの項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/ae46b6e6-d5c3-a071-b42d-89de388bd8f4.png)

（出典）[CartBuyerIdentity v2022-01](https://shopify.dev/api/storefront/2022-01/objects/CartBuyerIdentity#fields) を元に加工

</details>

<details>
<summary>
　　　　├　Cart <br/>
カートに参照元はありません。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/c09f7c13-a3e0-c38c-9fbe-b9b3de455a04.png)

（出典）[Cart v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Cart#connections) を元に加工

</details>


#### 商品（Products）

<details>
<summary>
Product <br/>
商品は、商品バリエーションの項目です。コレクションと紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/c4a6f432-81ba-d345-565a-989101193e55.png)
（出典）[Product v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Product#connections) を元に加工

</details>
<details>
<summary>
├　ProductVariant <br/>
商品バリエーションは、１件の注文、１件のチェックアウトの項目です。商品と紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/e9ccca1a-fa52-b5c3-4872-3ef3c23966f2.png)
（出典）[ProductVariant v2022-01](https://shopify.dev/api/storefront/2022-01/objects/ProductVariant#connections) を元に加工

</details>

<details>
<summary>
　　├　CheckoutLineItem <br/>
１件のチェックアウトは、チェックアウトと紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/25ed4b83-cf2b-9479-2761-3a84cf6c3aaf.png)

（出典）[CheckoutLineItem v2022-01](https://shopify.dev/api/storefront/2022-01/objects/CheckoutLineItem#fields) を元に加工

</details>

<details>
<summary>
　　　　├　Checkout <br/>
チェックアウトは、支払いの項目です。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/30774912-1a1c-469d-df62-09532ff76ffb.png)
（出典）[Checkout v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Checkout#connections) を元に加工

</details>

<details>
<summary>
　　　　　　├　Payment <br/>
支払いに参照元はありません。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/2cec0d0c-3d2f-d262-2782-2384a7e25aed.png)

（出典）[Payment v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Payment#fields) を元に加工

</details>


<details>
<summary>
　　├　OrderLineItem <br/>
１件の注文は、１件のフルフィルメントの項目です。注文と紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/17fed2a2-d07e-1388-881d-583bf554b901.png)

（出典）[OrderLineItem v2022-01](https://shopify.dev/api/storefront/2022-01/objects/OrderLineItem#fields) を元に加工

</details>

<details>
<summary>
　　　　├　FulfillmentLineItem <br/>
１件のフルフィルメントは、フルフィルメントと紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/b9cea6e7-e0b0-9555-d0be-ef43784d64c0.png)


（出典）[FulfillmentLineItem v2022-01](https://shopify.dev/api/storefront/2022-01/objects/FulfillmentLineItem#field-fulfillmentlineitem-lineitem) を元に加工

</details>



<details>
<summary>
⇔　Collection <br/>
コレクションは、商品と紐づきます。
</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127260/ecd473b7-7de2-ed1a-2051-9b23de2cda1f.png)
（出典）[Collections v2022-01](https://shopify.dev/api/storefront/2022-01/objects/Collection#connections) を元に加工

</details>


#### Hydrogen コンポーネント郡
Hydrogen で提供されているコンポーネント郡もデータ構造の参考になるかと思います。[こちらの記事でドキュメントを日本語訳している](https://qiita.com/t-kurasawa/items/b5f80f951fa574b17276#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E6%A9%9F%E8%83%BD)のでご覧ください。


### 認証

Storefront API は[未認証（unauthenticated）](https://shopify.dev/api/usage/authentication#unauthenticated-apis)で使えます。つまり、すべてのユーザーが読み取り専用でアクセスでき、ユーザー名やパスワードは必要ありません。Storefront API を有効にするアプリは、OAuth時、またはShopify管理画面での認証時に、関連する未認証のアクセススコープを明示的に要求する必要があります。

```@shopify/shopify-api Node.js
const adminApiClient = new Shopify.Clients.Rest(
  session.shop,
  session.accessToken,
);
const storefrontTokenResponse = await adminApiClient.post({
  path: 'storefront_access_tokens',
  type: DataType.JSON,
  data: {
    storefront_access_token: {
      title: 'This is my test access token',
    },
  },
});

const storefrontAccessToken =
  storefrontTokenResponse.body['storefront_access_token']['access_token'];
```

```Hydrogen shopify.config.js
// shopify.config.js
export default {
  storeDomain: '{shop}.myshopify.com',
  storefrontToken: {your_storefront_access_token},
  storefrontApiVersion: '2022-04',
};
```

### エンドポイントとクエリ

Storefront API は GraphQL で提供されているため１つのエンドポイントで、POST のみ受け付けています。バージョンは随時更新されていきます。

:::note info
POST
https://{store_name}.myshopify.com/api/2022-01/graphql.json
:::


```@shopify/shopify-api Node.js
// Load the access token as per instructions above
const storefrontAccessToken: string;
// Load the current session
const session = await Shopify.Utils.loadCurrentSession(req, res);
// StorefrontClient takes in the shop url and the Storefront Access Token for that shop.
const client = new Shopify.Clients.Storefront(
  session.shop,
  storefrontAccessToken,
);
// Use client.query and pass your query as `data`
const products = await client.query({
  data: `{
    products (first: 3) {
      edges {
        node {
          id
          title
        }
      }
    }
  }`,
});
```

```Hydrogen useShopQuery.js
import {useShopQuery} from '@shopify/hydrogen';

const queryString = gql`
query products {
  shop {
    products(first: 3) {
      edges {
        node {
          id
          title
        }
      }
    }
  }
}
`;

const {data} = useShopQuery({
  query: queryString,
});
```

### レート制限

Storefront APIは、時間でレートが制限されます。リクエスト数ではなく、リクエストが完了するまでにかかる時間が使用されます。詳細は[こちらを参照](https://shopify.dev/api/usage/rate-limits#the-leaky-bucket-algorithm)してください

|API|レート制限方式|Shopify|Shopify Plus|
|:-|:-|:-|:-|
|Storefront API (GraphQL)|時間ベースの制限|1リクエストあたり最小0.5秒、1ユーザーIPあたり60秒	|1リクエストあたり最小0.5秒、1ユーザーIPあたり120秒|

標準設定は以下
- バケットレートは60秒/アプリ/リクエストIPアドレス
- リークレートは1/second

[ステータスコード／エラーコードはこちらを参照](https://shopify.dev/api/storefront#status_and_error_codes)ください


## おわりに
GraphQL で提供されている Storefront API を利用することで Liquid を利用せずに JavaScript, React 等の使い慣れた言語で Shopify サイトを構築することが出来るようになります。[Hydrogen でヘッドレスコマースサイトを構築する記事](https://qiita.com/t-kurasawa/items/6f2b4c13fbb46fe7c519)も書いていますので是非ご覧ください。

| 更新日 | 更新内容 |
|:-|:-|
|2022-03-20|初版作成|
|2022-03-21|主要データ構造追記|

（出典）[GraphQL Storefront API](https://shopify.dev/api/storefront#top) を元に加筆・翻訳