【Shopify.dev和訳】API usage/Bulk operations
この記事について
この記事は、API usage/Bulkoperationsの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
Shopify アプリのご紹介
Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。
Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。
GraphQL AdminAPI を使用して一括操作を実行する
GraphQL Admin API を使用すると、一括操作を使用してデータを一括で非同期にフェッチできます。API は、大量のデータのページ付けを処理する際の複雑さを軽減するように設計されています。GraphQL AdminAPI スキーマで定義されている任意の接続フィールドを一括クエリできます。
結果を手動でページ付けしてクライアント側のスロットルを管理する代わりに、一括クエリ操作を実行できます。Shopify のインフラストラクチャは、クエリを実行するという大変な作業を行い、すべてのデータをダウンロードできる URL を提供します。
GraphQL Admin API は、単一の最上位フィールドのクエリを実行してから、返すフィールドを選択することをサポートしています。製品のバリエーションなど、接続をネストすることもできます。
アプリは、ショップごとに一度に 1 つの一括操作を実行するように制限されています。操作が完了すると、Shopify が URL で利用できるようにするJSONL file の形式で結果が配信されます。
一括クエリの導入
一括クエリを実行するための完全なフローについては後で説明しますが、以下は、すばやく開始するために使用できるいくつかの小さなコードスニペットです。
Step 1. クエリを送信する
bulkOperationRunQuery
ミューテーションを実行し、Shopify に必要な情報を指定します。
次のミューテーションは、products
の接続を照会し、各製品の ID とタイトルを返します。
POST /admin/api/2020-04/graphql.json
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
JSON response
{
"data": {
"bulkOperationRunQuery": {
"bulkOperation": {
"id": "gid:\/\/shopify\/BulkOperation\/720918",
"status": "CREATED"
},
"userErrors": []
}
},
...
}
Step 2. オペレーションのステータスをポーリングする
操作の実行中に、currentBulkOperation
フィールドを使用して進行状況を確認するためにポーリングする必要があります。objectCount
フィールドは増分して操作の進行状況を示し、status
フィールドは操作が完了したかどうかを返します。
POST /admin/api/2020-04/graphql.json
query {
currentBulkOperation {
id
status
errorCode
createdAt
completedAt
objectCount
fileSize
url
partialDataUrl
}
}
JSON response
{
"data": {
"currentBulkOperation": {
"id": "gid:\/\/shopify\/BulkOperation\/720918",
"status": "COMPLETED",
"errorCode": null,
"createdAt": "2019-08-29T17:16:35Z",
"completedAt": "2019-08-29T17:23:25Z",
"objectCount": "57",
"fileSize": "358",
"url": "https:\/\/storage.googleapis.com\/shopify\/dyfkl3g72empyyoenvmtidlm9o4g?<params>",
"partialDataUrl": null
}
},
...
}
Step 3. データを取得する
操作が完了すると、URL
フィールドで指定された URL から JSONL 出力ファイルをダウンロードできます。クエリで結果が生成されなかった場合、url
フィールドはnull
を返します。
返されるファイルの詳細については結果データのダウンロード を、解析方法については JSONL ファイル形式JSONL file format を参照してください。
一括クエリワークフロー
以下は、一括クエリを作成するための高レベルのワークフローです。
-
潜在的な一括操作を特定する.
新規または既存のクエリを使用できますが、大量のデータが返される可能性があります。接続ベースのクエリが最適です。 -
Shopify GraphiQL アプリ.を使用してクエリをテストします。
-
bulkOperationRunQuery
のための新しいミューテーションドキュメントを作成します 。 -
ミューテーションの
query
の値としてクエリを含めます。 -
ミューテーションを実行します。
-
status
フィールドに操作が実行されなくなったことが示されるまで、一括操作をポーリングします。objectCount
フィールドを使用して、操作の進行状況を確認できます 。 -
URL
フィールドに指定された URL で JSONL ファイルをダウンロードします
潜在的な一括クエリを特定する
大量のデータを返す可能性があり、一括操作のメリットを享受できる新規または既存のクエリを特定します。
結果のすべてのページを取得するためにページ付けを使用するクエリは、最も一般的な候補です。
以下のクエリ例は、2019 年 1 月 1 日以降に作成されたストアの最初の 50 個の商品からいくつかの基本情報を取得します。
{
products(query: "created_at:>=2020-01-01 AND created_at:<2020-05-01", first: 50) {
edges {
cursor
node {
id
createdAt
updatedAt
title
handle
descriptionHtml
productType
options {
name
position
values
}
priceRange {
minVariantPrice {
amount
currencyCode
}
maxVariantPrice {
amount
currencyCode
}
}
}
}
pageInfo {
hasNextPage
}
}
}
一括操作を書く
上記のクエリを一括クエリに変換するには、bulkOperationRunQuery
ミューテーションを使用します。query
のバリューなしでスケルトンミューテーションから始めるのが最も簡単です。
mutation {
bulkOperationRunQuery(
query: """
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
- 三重引用符( "" ")は、GraphQL で複数行の文字列を定義します。
- 一括操作の ID が返されるため、操作をポーリングできます。
- エラーメッセージを取得するために、
userErrors
フィールドが返されます。
元のサンプルクエリをミューテーションに貼り付けてから、オプションでいくつかの小さな変更を加えます。
-
first
の引数はオプションであり、存在する場合は無視されるため、削除できます。 -
cursor
フィールドとpageInfo
フィールドもオプションであり、存在する場合は無視されるため、削除できます。
mutation {
bulkOperationRunQuery(
query: """
{
products(query: "created_at:>=2020-01-01 AND created_at:<2020-05-01") {
edges {
node {
id
createdAt
updatedAt
title
handle
descriptionHtml
productType
options {
name
position
values
}
priceRange {
minVariantPrice {
amount
currencyCode
}
maxVariantPrice {
amount
currencyCode
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
ミューテーションが成功した場合、応答は次の例のようになります。
{
"data": {
"bulkOperationRunQuery": {
"bulkOperation": {
"id": "gid:\/\/shopify\/BulkOperation\/1",
"status": "CREATED"
},
"userErrors": []
}
},
...
}
実行中の一括操作をポーリングする
一括操作は非同期で長時間実行されるため、いつ完了するかを調べるためにポーリングする必要があります。これを行う最も簡単な方法は、currentBulkOperation
フィールドを照会することです。
{
currentBulkOperation {
id
status
errorCode
createdAt
completedAt
objectCount
fileSize
url
partialDataUrl
}
}
このフィールドは、認証されたアプリとショップに対して(ステータスに関係なく)作成された最新の一括操作を返します。 ID で特定の操作を検索する場合は、node
フィールドを使用できます。
{
node(id: "gid://shopify/BulkOperation/1") {
... on BulkOperation {
id
status
errorCode
createdAt
completedAt
objectCount
fileSize
url
partialDataUrl
}
}
}
予想されるデータ量に基づいて、ポーリング間隔を調整できます。たとえば、現在手動 でページ付けクエリを実行していて、すべての商品データを取得するのに 1 時間かかる場合、それは一括操作時間の概算として役立ちます。この状況では、1 分のポーリング間隔が 10 秒ごとよりもおそらく良いでしょう。
その他の可能な操作ステータスについては、BulkOperationStatus
リファレンスを参照してください。
操作の進行状況を確認する
ポーリングは、操作が完了したかどうかを確認するのに役立ちますが、objectCount
フィールドを使用して操作の進行状況を確認するためにも使用できます。
{
currentBulkOperation {
status
objectCount
url
}
}
たとえば、1 か月で作成されたすべての商品をクエリしようとしていて、オブジェクト数が予想数を超えている場合は、クエリ条件が間違っていることを示している可能性があります。その場合、現在の操作をキャンセルして、別のクエリで新しい操作を実行することをお勧めします。
結果データをダウンロードする
操作の実行が終了すると、結果データが利用可能になります。
操作が正常に完了すると、url
フィールドにデータをダウンロードできる URL が含まれます。操作が失敗したが、失敗が発生する前に一部のデータが取得された場合、partialDataUrl
フィールドで指定された URL で部分的に完全な出力ファイルを使用できます。いずれの場合も、返される URL は署名(認証)され、1 週間後に期限切れになります。
データをダウンロードしたので、JSONL 形式に従ってデータを解析します。
JSONL データ形式
通常の(バルクではない)GraphQL 応答は JSON です。応答構造はクエリ構造を反映しているため、ネストされたオブジェクトが多数含まれる単一の JSON オブジェクトになります。ほとんどの標準的な JSON パーサーでは、文字列またはファイル全体をメモリに読み込む必要があります。これにより、応答が大きい場合に問題が発生する可能性があります。
一括操作は大規模なデータセットをフェッチするように特別に設計されているため、クライアントがデータを消費する方法に柔軟性を持たせるために、応答データに JSON Lines (JSONL)形式を選択しました。JSONL は JSON に似ていますが、各行は独自の有効な JSON オブジェクトです。メモリ消費の問題を回避するために、ほとんどの言語にあるファイルストリーミング機能を使用して、ファイルを一度に 1 行ずつ解析できます。
ファイルの各行は、接続で返されるノードオブジェクトです。ノードにネストされた接続がある場合、各子ノードは次の行の独自のオブジェクトに抽出されます。たとえば、一括操作では、次のクエリを使用して、製品とそのネストされた variants 型のリストを取得できます。
{
products {
edges {
node {
id
variants {
edges {
node {
id
title
}
}
}
}
}
}
}
JSONL の結果では、各製品オブジェクトの後に、新しい行にその variants 型オブジェクトが続きます。各接続タイプの順序は保持され、ネストされたすべての接続はファイル内の親の後に表示されます。ただし、子ノードは親の直後に表示されない場合があります。たとえば、次の結果では、タイトル52
の製品 variants は、ファイルの最初の製品の子です。
{"id":"gid://shopify/Product/1921569226808"}
{"id":"gid://shopify/ProductVariant/19435458986040","title":"70","__parentId":"gid://shopify/Product/1921569226808"}
{"id":"gid://shopify/Product/1921569259576"}
{"id":"gid://shopify/ProductVariant/19435459018808","title":"34","__parentId":"gid://shopify/Product/1921569259576"}
{"id":"gid://shopify/Product/1921569292344"}
{"id":"gid://shopify/ProductVariant/19435459051576","title":"Default Title","__parentId":"gid://shopify/Product/1921569292344"}
{"id":"gid://shopify/Product/1921569325112"}
{"id":"gid://shopify/ProductVariant/19435459084344","title":"36","__parentId":"gid://shopify/Product/1921569325112"}
{"id":"gid://shopify/Product/1921569357880"}
{"id":"gid://shopify/ProductVariant/19435459117112","title":"47","__parentId":"gid://shopify/Product/1921569357880"}
{"id":"gid://shopify/ProductVariant/19435458986123","title":"52","__parentId":"gid://shopify/Product/1921569226808"}
ネストされた接続は応答データ構造にネストされなくなったため、結果にはオブジェクトの親への参照である__parentId
フィールドが含まれます。このフィールドは API スキーマに存在しないため、明示的にクエリすることはできません。一括操作結果に自動的に含まれます。
JSONL ファイルを逆に読む
JSONL ファイルを逆に読み取ると、子ノードのグループ化が容易になり、親ノードの後に 表示されるノードが失われる。たとえば、バリアントを収集している間、variants が属する製品に到達したときに、ファイルのさらに上にバリアントが存在することはありません。JSONL ファイルをダウンロードした後、それを逆に読み取り、それを解析して、親ノードが検出される前に子ノードが追跡されるようにします。
例
ほとんどのプログラミング言語には、ファイル全体がメモリに読み込まれないように、一度に 1 行ずつファイルを読み取る機能があります。この機能は、JSONL データファイルを処理するときに利用する必要があります。
これは、JSONL ファイルをロードして解析する適切な方法を示す Ruby の簡単な例です。
# Efficient: reads the file a single line at a time
File.open(file) do |f|
f.each do |line|
JSON.parse(line)
end
end
# Inefficient: reads the entire file into memory
jsonl = File.read(file)
jsonl.each_line do |line|
JSON.parse(line)
end
100MB の JSONL ファイルを使用した場合の違いを示すために、「良い」バージョンは 2.5MB のメモリしか消費しませんが、「悪い」バージョンは 100MB(ファイルサイズに等しい)を消費します。
他の言語:
- NodeJS:
readline
- Python: built-in iterator
- PHP:
fgets
実行の失敗
フィールドをクエリする権限がないなど、通常の GraphQL クエリが失敗する理由のいずれかにより、一括操作が失敗する可能性があります。このため、最初にクエリを通常どおり実行して、クエリが機能することを確認することをお勧めします。一括操作でクエリが失敗した場合よりも、はるかに優れたエラーフィードバックが得られます。
一括操作が失敗した場合、そのstatus
フィールドはFAILED
を返し、errorCode
フィールドには次のコードが含まれます。
-
ACCESS_DENIED
:アクセススコープがありません。クエリを通常どおり(一括操作以外で)実行して、問題の原因となっているフィールドの詳細を取得します。 -
INTERNAL_SERVER_ERROR
:サーバーで問題が発生し、エラーが通知されました。これらのエラーは断続的に発生する可能性があるため、クエリの送信を再試行できます。 -
TIMEOUT
:実行中に 1 つ以上のクエリタイムアウトが発生しました。クエリを正常に実行できるように、クエリからいくつかのフィールドを削除してみてください。これらのタイムアウトは断続的に発生する可能性があるため、 クエリの送信を再試行できます。
その他の考えられる操作エラーコードについては、BulkOperationErrorCode
リファレンスを参照してください。
キャンセルされた操作
一括操作が停止した場合、Shopify によってキャンセルされる可能性があります。一括操作がキャンセルされた後、CANCELED
のstatus
が返されます。クエリを再送信することで、キャンセルされた一括操作を再試行できます。
操作のキャンセル
進行中の一括操作をキャンセルするには、操作 ID でbulkOperationCancel
ミューテーションを使用します。
mutation {
bulkOperationCancel(id: "gid://shopify/BulkOperation/1") {
bulkOperation {
status
}
userErrors {
field
message
}
}
}
レート制限
現在、ショップごとに(アプリごとに)アクティブな(実行中の)一括操作は常に1 つだけです。この制限は、操作が非同期で長時間実行されるために適用されます。
一括操作が AdminAPI のレート制限内にどのように収まるか
バルク操作は、bulkOperationRunQuery
ミューテーション内にクエリ文字列を指定することにより、API コンシューマーであるユーザーによって開始されます。次に、Shopify はそのquery
文字列を一括操作として非同期に実行します。 BulkOperationRunQuery
ミューテーションとバルクquery
文字列自体のこの違いにより、レート制限の適用方法も決まります。ユーザーが行った GraphQL リクエストは、通常の API リクエストとしてカウントされ、レート制限の対象となりますが、一括操作クエリの実行は対象外です。
次の例では、(他のミューテーションと同様に)ミューテーションリクエストのコストが請求されますが、Shopify で一括操作として実行する製品タイトルのquery
については請求されません。
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
title
}
}
}
}
"""
) {
bulkOperation {
id
}
}
}
操作の作成、ステータスのポーリング、またはキャンセルのために低コストのリクエストを行うだけなので、一括操作は、標準のページ付けクエリと比較して、データをクエリするための非常に効率的な方法です。
動作制限
一括操作クエリには接続を含める必要があります。クエリが接続を使用しない場合は、通常の同期 GraphQL クエリとして実行する必要があります。
一括操作には、いくつかの追加の制限があります。
- クエリ内の合計接続数は最大 5 つです。
- 最上位の
node
および``nodes`フィールドは使用できません。 - ネストされた接続の場合、最大 2 レベルの深さ。たとえば、ネストされた接続には 3 つのレベルがあるため、以下は無効です。
{
products {
edges {
node {
id
variants {
# nested level 1
edges {
node {
id
images {
# nested level 2
edges {
node {
id
metafields {
# nested level 3 (invalid)
edges {
node {
value
}
}
}
}
}
}
}
}
}
}
}
}
}
BulkOperationRunQuery
ミューテーションは、提供されたクエリを検証し、userErrors
フィールドを使用してエラーを提供します。
GraphQL クエリの柔軟性が許可されているものと提供されていないものの完全な例を提供するのは難しいので、いくつか試してみて、何が機能し、何が機能しないかを確認してください。まだサポートされていない有用なクエリを見つけた場合は、forumsでお知らせください。一般的な使用例を収集できます。
次のステップ
- 一括操作の作成と管理の詳細については、reference documentationを参照してください。
- 大量のデータを非同期で一括インポートする方法を学びます。
GraphQL AdminAPI を使用したデータの一括インポート
従来の同期 API を使用して大量のデータをインポートすると、処理が遅く、実行が複雑になり、管理が困難になります。GraphQL ミューテーションを手動で複数回実行し、クライアント側のスロットルを管理する代わりに、バルクミューテーション操作を実行できます。
GraphQL Admin API を使用すると、大量のデータを非同期で一括インポートできます。操作が完了すると、Shopify が URL で利用できるようにするJSON Lines (JSONL)ファイルで結果が配信されます。
このガイドでは、bulkOperationRunMutation
を紹介し、それを使用してデータを Shopify に一括インポートする方法を示します。
要件
- 開発ストアでの 製品、製品 variants、およびコレクションの作成に精通している。
- GraphQL AdminAPI を使用した一括操作の実行に精通している。
- API バージョン 2021-07 以降を使用しています。
制限事項
- ショップごとに一度に実行できるのは、各タイプ(
bulkOperationRunMutation
またはbulkOperationRunQuery
)の一括操作を 1 つだけです。
この制限は、操作が非同期で長時間実行されるために適用されます。ショップに対して後続のバルクミューテーション操作を実行するには、実行中の操作をキャンセルするか、実行が終了するのを待つ必要があります。
-
一度に
bulkOperationRunMutation
に提供できる GraphQLAPI ミューテーションは 1 つだけです。 -
BulkOperationRunMutation
に渡されるミューテーションは、GraphQL AdminAPI スキーマによって定義される 1 つの接続フィールドに制限されます。
データの一括インポートの仕組み
バルク操作を開始するには、bulkOperationRunMutation
にミューテーション文字列を指定します。次に、Shopify は、そのミューテーション文字列を一括操作として非同期に実行します。
作成するほとんどの GraphQLAdmin API リクエストにはレート制限が適用されますが、bulkOperationRunMutation
リクエストには適用されません。操作の作成、ステータスのポーリング、またはキャンセルのために低コストのリクエストを行うだけなので、バルクミューテーション操作は、標準の GraphQLAPI リクエストと比較してデータを作成するための効率的な方法です。
次の図は、Shopify へのデータの一括インポートに関連する手順を示しています。
- JSONL ファイルを作成し、GraphQL 変数を含めます :ミューテーションの変数を JSONL ファイル形式で含めます。 JSONL ファイルの各行は、1 つの入力ユニットを表します。ミューテーションは、入力ファイルの各行で 1 回実行されます。
-
ファイルを Shopify にアップロードする:ファイルをアップロードする前に、
stagedUploadsCreate
ミューテーションを実行してリンクを予約する必要があります。スペースが予約された後、stagedUploadsCreate
応答から返された情報を使用して要求を行うことにより、ファイルをアップロードできます。 -
一括変更操作の作成:ファイルがアップロードされたら、
bulkOperationRunMutation
を実行して一括変更操作を作成できます。bulkOperationRunMutation
は、最後のステップでアップロードされた変数のファイルを使用して、提供された GraphQL API ミューテーションを実行することにより、データを一括でインポートします。 -
操作のステータスをポーリングする:操作の実行中に、
currentBulkOperation
フィールドを使用して進行状況を確認するためにポーリングする必要があります。bulkOperation
オブジェクトのobjectCount
フィールドは、操作の進行状況を示すために増分し、status
フィールドは、操作が完了したかどうかを示すブール値を返します。 -
結果の取得:一括変更操作が完了すると、
URL
フィールドで指定された URL から JSONL 出力ファイルをダウンロードできます。
JSONL ファイルを作成し、GraphQL 変数を含めます
GraphQL 変数を新しい JSONL ファイルに追加するときは、対応する一括操作 GraphQLAPI によって受け入れられるように変数をフォーマットする必要があります。入力変数の形式は、GraphQL AdminAPI スキーマと一致する必要があります。
たとえば、大量の製品をインポートしたい場合があります。製品の各属性は、GraphQL 入力オブジェクト ProductInput
で定義された既存のフィールドにマップする必要があります。JSONL ファイルでは、各行は 1 つの製品入力を表します。 GraphQL Admin API は、入力ファイルの各行で 1 回実行されます。入力オブジェクトの構造がどれほど複雑であっても、1 つの入力は 1 行だけを占める必要があります。
次の例は、10 個の製品をまとめて作成するために使用されるサンプル JSONL ファイルを示しています。
{ "input": { "title": "Sweet new snowboard 1", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 2", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 3", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 4", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 5", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 6", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 7", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 8", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 9", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 10", "productType": "Snowboard", "vendor": "JadedPixel" } }
ファイルを Shopify にアップロードします
JSONL ファイルを作成し、GraphQL 変数を含めたら、ファイルを Shopify にアップロードできます。ファイルをアップロードする前に、まずアップロード URL とパラメーターを生成する必要があります。
アップロードされた URL とパラメータを生成します
stagedUploadsCreate
ミューテーションを使用して、アップロードの認証に必要な値を生成できます。ミューテーションは、stagedMediaUploadTarget
インスタンスの配列を返します。
stagedMediaUploadTarget
のインスタンスには、次の主要なプロパティがあります。
-
parameters
:アップロードリクエストの認証に使用するパラメータ。 -
url
:GraphQL 変数を含む JSONL ファイルをアップロードできる署名付き URL。
ミューテーションは、次のフィールドを持つタイプstagedUploadInput
の入力を受け入れます。
フィールド | 型 | 説明 |
---|---|---|
resource |
enum |
アップロードするリソースタイプを指定します。 BulkOperationRunMutation を使用するには、リソースタイプがBULK_MUTATION_VARIABLES である必要があります。 |
filename |
string |
アップロードするファイルの名前。 |
mimeType |
string |
アップロードするファイルのmedia type。 BulkOperationRunMutation を使用するには、mimeType が「text / jsonl」 である必要があります。 |
httpMethod |
enum |
段階的アップロードで使用される HTTP メソッド。 BulkOperationRunMutation を使用するには、httpMethod がPOST である必要があります。 |
例
次の例では、stagedUploadsCreate
ミューテーションを使用して、JSONL ファイルをアップロードし、bulkOperationRunMutation
によって消費されるために必要な値を生成します。最初に変数なしでstagedUploadsCreate
ミューテーションを実行してから、JSONL データを使用して段階的なアップロード URL に POST リクエストを個別に送信する必要があります。
リクエスト
POST /admin/api/2021-07/graphql.json
mutation {
stagedUploadsCreate(
input: {
resource: BULK_MUTATION_VARIABLES
filename: "bulk_op_vars"
mimeType: "text/jsonl"
httpMethod: POST
}
) {
userErrors {
field
message
}
stagedTargets {
url
resourceUrl
parameters {
name
value
}
}
}
}
JSON response:
{
"data": {
"stagedUploadsCreate": {
"userErrors": [],
"stagedTargets": [
{
"url": "https://shopify.s3.amazonaws.com",
"resourceUrl": null,
"parameters": [
{
"name": "key",
"value": "tmp/21759409/bulk/89e620e1-0252-43b0-8f3b-3b7075ba4a23/bulk_op_vars"
},
{
"name": "Content-Type",
"value": "text/jsonl"
},
{
"name": "success_action_status",
"value": "201"
},
{
"name": "acl",
"value": "private"
},
{
"name": "policy",
"value": "eyJleHBpcmF0aW9uIjoiMjAyMS0wMS0yOFQyMDowNTo0NloiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJzaG9waWZ5In0sWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsMSwyMDk3MTUyMF0seyJrZXkiOiJ0bXAvMjE3NTk0MDkvYnVsay84OWU2MjBlMS0wMjUyLTQzYjAtOGYzYi0zYjcwNzViYTRhMjMvYnVsa19vcF92YXJzIn0seyJDb250ZW50LVR5cGUiOiJ0ZXh0L2pzb25sIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDEifSx7ImFjbCI6InByaXZhdGUifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSllNNTU1S1ZZRVdHSkRLUS8yMDIxMDEyOC91cy1lYXN0LTEvczMvYXdzNF9yZXF1ZXN0In0seyJ4LWFtei1hbGdvcml0aG0iOiJBV1M0LUhNQUMtU0hBMjU2In0seyJ4LWFtei1kYXRlIjoiMjAyMTAxMjhUMTkwNTQ2WiJ9XX0="
},
{
"name": "x-amz-credential",
"value": "AKIAJYM555KVYEWGJDKQ/20210128/us-east-1/s3/aws4_request"
},
{
"name": "x-amz-algorithm",
"value": "AWS4-HMAC-SHA256"
},
{
"name": "x-amz-date",
"value": "20210128T190546Z"
},
{
"name": "x-amz-signature",
"value": "5d063aac44a108f2e38b8294ca0e82858e6f44baf835eb81c17d37b9338b5153"
}
]
}
]
}
},
"extensions": {
"cost": {
"requestedQueryCost": 11,
"actualQueryCost": 11
}
}
}
JSON ファイルをアップロードする
アップロード用のパラメーターと URL を生成した後、POST リクエストを使用して JSONL ファイルをアップロードできます。マルチパートフォームを使用し、すべてのパラメーターをフォーム入力としてリクエスト本文に含める必要があります。
マルチパートフォームのパラメーターを生成するには、stagedUploadsCreate
ミューテーションから返されたパラメーターから始めます。次に、添付ファイルを追加します。
POST request
curl --location --request POST 'https://shopify.s3.amazonaws.com' \
--form 'key="tmp/21759409/bulk/89e620e1-0252-43b0-8f3b-3b7075ba4a23/bulk_op_vars"' \
--form 'x-amz-credential="AKIAJYM555KVYEWGJDKQ/20210128/us-east-1/s3/aws4_request"' \
--form 'x-amz-algorithm="AWS4-HMAC-SHA256"' \
--form 'x-amz-date="20210128T190546Z"' \
--form 'x-amz-signature="5d063aac44a108f2e38b8294ca0e82858e6f44baf835eb81c17d37b9338b5153"' \
--form 'policy="eyJleHBpcmF0aW9uIjoiMjAyMS0wMS0yOFQyMDowNTo0NloiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJzaG9waWZ5In0sWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsMSwyMDk3MTUyMF0seyJrZXkiOiJ0bXAvMjE3NTk0MDkvYnVsay84OWU2MjBlMS0wMjUyLTQzYjAtOGYzYi0zYjcwNzViYTRhMjMvYnVsa19vcF92YXJzIn0seyJDb250ZW50LVR5cGUiOiJ0ZXh0L2pzb25sIn0seyJzdWNjZXNzX2FjdGlvbl9zdGF0dXMiOiIyMDEifSx7ImFjbCI6InByaXZhdGUifSx7IngtYW16LWNyZWRlbnRpYWwiOiJBS0lBSllNNTU1S1ZZRVdHSkRLUS8yMDIxMDEyOC91cy1lYXN0LTEvczMvYXdzNF9yZXF1ZXN0In0seyJ4LWFtei1hbGdvcml0aG0iOiJBV1M0LUhNQUMtU0hBMjU2In0seyJ4LWFtei1kYXRlIjoiMjAyMTAxMjhUMTkwNTQ2WiJ9XX0="' \
--form 'acl="private"' \
--form 'Content-Type="text/jsonl"' \
--form 'success_action_status="201"' \
--form 'file=@"/Users/username/Documents/bulk_mutation_tests/products_long.jsonl"'
GraphQL variables in JSONL file
{ "input": { "title": "Sweet new snowboard 1", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 2", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 3", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 4", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 5", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 6", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 7", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 8", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 9", "productType": "Snowboard", "vendor": "JadedPixel" } }
{ "input": { "title": "Sweet new snowboard 10", "productType": "Snowboard", "vendor": "JadedPixel" } }
バルクミューテーション操作を作成する
ファイルをアップロードした後、bulkOperationRunMutation
を実行して、データを一括でインポートできます。対応するミューテーションと前の手順で取得した URL を指定する必要があります。
bulkOperationRunMutation
ミューテーションは、次の引数を取ります。
フィールド | 型 | 説明 |
---|---|---|
mutation |
string |
一括で実行する GraphQLAPI ミューテーションを指定します。有効な値:productCreate 、collectionCreate 、productUpdate 、productUpdateMedia 、productVariantUpdate
|
stagedUploadPath |
string |
stagedUploadsCreate によって使用される JSONL 形式の入力ファイルへのパス |
例
次の例では、次のproductCreate
ミューテーションを一括で実行します。
mutation call($input: ProductInput!) {
productCreate(input: $input) {
product {
id
title
variants(first: 10) {
edges {
node {
id
title
inventoryQuantity
}
}
}
}
userErrors {
message
field
}
}
}
productCreate
ミューテーションを一括で実行するには、ミューテーションを文字列としてbulkOperationRunMutation
に渡します。
Request
POST /admin/api/2021-07/graphql.json
mutation {
bulkOperationRunMutation(
mutation: "mutation call($input: ProductInput!) { productCreate(input: $input) { product {id title variants(first: 10) {edges {node {id title inventoryQuantity }}}} userErrors { message field } } }"
stagedUploadPath: "tmp/21759409/bulk/89e620e1-0252-43b0-8f3b-3b7075ba4a23/bulk_op_vars"
) {
bulkOperation {
id
url
status
}
userErrors {
message
field
}
}
}
JSON response:
{
"data": {
"bulkOperationRunMutation": {
"bulkOperation": {
"id": "gid://shopify/BulkOperation/206005076024",
"url": null,
"status": "CREATED"
},
"userErrors": []
}
},
"extensions": {
"cost": {
"requestedQueryCost": 10,
"actualQueryCost": 10
}
}
}
操作のステータスをポーリングします
一括操作は非同期であり、大きな入力ファイルの場合は長時間実行される可能性があるため、ポーリングを実行して、いつ完了したかを確認する必要があります。ポーリングする最も簡単な方法は、currentBulkOperation
フィールドを照会することです。
インポートするデータの量に基づいて、ポーリング間隔を調整できます。その他の考えられる操作ステータスについては、BulkOperationStatus
リファレンスドキュメントを参照してください。
操作のステータスをポーリングするには、次のリクエスト例を使用します。
Request
POST /admin/api/2021-07/graphql.json
query {
currentBulkOperation(type: MUTATION) {
id
status
errorCode
createdAt
completedAt
objectCount
fileSize
url
partialDataUrl
}
}
JSONresponse
{
"data": {
"currentBulkOperation": {
"id": "gid://shopify/BulkOperation/206005076024",
"status": "COMPLETED",
"errorCode": null,
"createdAt": "2021-01-28T19:10:59Z",
"completedAt": "2021-01-28T19:11:09Z",
"objectCount": "16",
"fileSize": "6155",
"url": "https://storage.googleapis.com/shopify-tiers-assets-prod-us-east1/iqtpj52yuoa7prkbpzp9gwn27kw3?GoogleAccessId=assets-us-prod%40shopify-tiers.iam.gserviceaccount.com&Expires=1612465869&Signature=KOhlcYhLve3NLr6rfVbAeY02crFAM3rMrDNfTSlgT%2FScI%2B8o%2B%2FdO99F3UseC837uWA6FzfrNhxdRNqhBN%2F8ekBTW7IyPRD6ho5phfE8MTaev4ltQrJygJTDbjXfX5KLJOuY8siH%2FDrc4gctZsMsNaf2%2FYp%2FaDzBzjfxJge8i8he69t0uZ39FBXrMxCeMVd6lU8%2FbgMuO80rTHjgI%2BlC8g2%2FWiHyq5rSTDLIxxGWRCddMfPcaivdWVdMubMa0wOt9W9R2mfjuTAgUBexUkJwhvrkdof%2Bg00gU1g4dIBWlUSO5D9tdrv9bmIy7FceopNufrpwnD1NXU8Narsx2yEQ6aA%3D%3D&response-content-disposition=attachment%3B+filename%3D%22bulk-206005076024.jsonl%22%3B+filename%2A%3DUTF-8%27%27bulk-206005076024.jsonl&response-content-type=application%2Fjsonl",
"partialDataUrl": null
}
},
"extensions": {
"cost": {
"requestedQueryCost": 1,
"actualQueryCost": 1
}
}
}
結果を取得する
バルクミューテーション操作が終了したら、結果データファイルをダウンロードできます。
操作が正常に完了すると、url
フィールドにはデータファイルをダウンロードできる URL が含まれます。操作が失敗したが、失敗が発生する前に一部のデータが取得された場合、partialDataUrl
フィールドで指定された URL で部分的に完全なデータファイルを利用できます。
いずれの場合も、返された URL は認証され、1 週間後に期限切れになります。
データをダウンロードしたら、JSONL 形式に従って解析できます。入力ファイルと応答ファイルの両方が JSONL にあるため、最終的なアセットファイルの各行は、入力ファイルの対応する行でミューテーションを実行したときの応答を表します。
操作の成功
次の例は、正常に作成された製品の応答を示しています。
{
"data": {
"productCreate": {
"product": {
"id": "gid://shopify/Product/5602345320504",
"title": "Monday morning snowboard 1",
"variants": {
"edges": [
{
"node": {
"id": "gid://shopify/ProductVariant/35645836853304",
"title": "First",
"inventoryQuantity": 0
}
},
{
"node": {
"id": "gid://shopify/ProductVariant/35645836886072",
"title": "Second",
"inventoryQuantity": 0
}
}
]
}
},
"userErrors": []
}
},
"__lineNumber": 0
}
操作の失敗
特定の API にアクセスする権限がないなど、通常の GraphQL API ミューテーションが失敗する理由のいずれかにより、一括操作が失敗する可能性があります。このため、最良のアプローチは、最初に単一の GraphQL ミューテーションを実行して、バルク操作の一部としてミューテーションを実行する前に、それが機能することを確認することです。
一括操作が失敗した場合、そのstatus
フィールドはFAILED
を返し、errorCode
フィールドは次のいずれかのコードを返します。
-
ACCESS_DENIED
:アクセススコープがありません。ミューテーションを通常どおり(一括操作の外で)実行して、問題の原因となっているフィールドの詳細を取得します。 -
INTERNSL_SERVER_ERROR
:Shopify のサーバーで問題が発生し、エラーが通知されました。これらのエラーは断続的に発生する可能性があるため、もう一度リクエストしてみてください。 -
TIMEOUT
:実行中に 1 つ以上のミューテーションタイムアウトが発生しました。クエリを正常に実行できるように、クエリからいくつかのフィールドを削除してみてください。これらのタイムアウトは断続的に発生する可能性があるため、クエリの送信を再試行できます。
その他の考えられる操作エラーコードについては、BulkOperationErrorCode
リファレンスドキュメントを参照してください。
検証エラー
入力の形式が正しいが、1 つ以上の値が製品作成サービスの検証に失敗した場合、応答は次のようになります。
{"data"=>{"productCreate"=>{"userErrors"=>[{"message"=>"Some error message", "field"=>["some field"]}]}}}
認識できないフィールドエラー
入力に認識できないフィールドがある場合、応答は次のようになります。
{"errors"=>[{"message"=>"Variable input of type ProductInput! was provided invalid value for myfavoriteaddress (Field is not defined on ProductInput)", "locations"=>[{"line"=>1, "column"=>13}], "extensions"=>{"value"=>{"myfavoriteaddress"=>"test1"}, "problems"=>[{"path"=>["myfavoriteaddress"], "explanation"=>"Field is not defined on ProductInput"}]}}]}
操作をキャンセルする
進行中のバルク操作をキャンセルするには、 bulkOperationCancel
ミューテーションを実行し、操作 ID を入力変数として指定します。
Request
POST /admin/api/2021-07/graphql.json
mutation {
bulkOperationCancel(id: "gid://shopify/BulkOperation/1") {
bulkOperation {
status
}
userErrors {
field
message
}
}
}
次のステップ
- 一括操作の作成と管理の詳細については、reference documentation を参照してください。
- バルク操作を使用して、データを一括で非同期にフェッチする方法を学習します。
Shopify アプリのご紹介
Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。
Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。
Discussion