Play ゲームサービスの Publishing API を使用して画像をアップロードする

Play ゲームサービスの Publishing API を使用して、ゲームリソースの画像をアップロードできます。

アップロード オプション

Play ゲームサービスの Publishing API では、特定の種類のバイナリデータ(メディア)をアップロードできます。アップロードできるデータの具体的な特性については、メディア アップロードをサポートする方法のリファレンス ページに記載されています。

  • アップロード ファイルの最大サイズ: この方法で保存できるデータ量の上限。

  • 使用可能なメディア MIME タイプ: この方法で保存できるバイナリデータのタイプ。

アップロード リクエストは次のいずれかの方法で行えます。使用するメソッドは、uploadType リクエスト パラメータで指定します。

  • シンプル アップロードuploadType=media)。比較的小さいファイル(例: 5 MB 以下)を高速で転送します。

  • マルチパート アップロードuploadType=multipart)。比較的小さいファイルをメタデータとともに高速で転送します。ファイルとそのファイルを記述するメタデータのすべてを 1 つのリクエストにまとめて転送します。

  • 再開可能アップロードuploadType=resumable)。比較的大きいファイルで特に重要な、信頼性の高い転送を行います。この方法ではセッション開始リクエストを使用します。必要に応じてメタデータを追加できます。これは、ほとんどのアプリで使用できるおすすめの方法です。アップロードごとに HTTP リクエストを 1 つ追加する手間を厭わなければ、比較的小さいファイルでも使用できます。

メディアをアップロードするときは、特別な URI を使用します。実際、メディア アップロードをサポートする方法では、次の 2 つの URI エンドポイントがあります。

  • メディア用の /upload URI。アップロード エンドポイントの形式は、標準のリソース URI に接頭辞「/upload」を付けたものです。この URI は、メディアデータそのものを転送する場合に使用します。

    例: POST /upload/games/v1configuration/images/resourceId/imageType/imageType

  • メタデータ用の標準のリソース URI。リソースにデータ フィールドが含まれている場合は、それらのフィールドを使用して、アップロードするファイルを記述するメタデータを格納します。この URI は、メタデータの値を作成または更新する場合に使用できます。

    例: POST /games/v1configuration/images/resourceId/imageType/imageType

シンプル アップロード

ファイルをアップロードする最も簡単な方法は、シンプル アップロード リクエストを行うことです。この方法は次のいずれかに該当する場合におすすめです。

  • ファイルが小さく、接続が失敗したときはファイル全体を再度アップロードできる場合。

  • 送信するメタデータがない場合。たとえば、アップロードするリソースのメタデータを別のリクエストで送信することを予定している場合や、メタデータがサポートされていないか利用できない場合などです。シンプル アップロードを使用するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=media を追加します。次に例を示します。

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media

シンプル アップロード リクエストの作成時に使用する HTTP ヘッダーの内容は次のとおりです。

  • Content-Type: アップロード方法で使用可能なアップロード メディア データタイプのいずれかに設定します(Publishing API のリファレンスをご覧ください)。

  • Content-Length: アップロードするバイト数に設定します。チャンク形式の転送エンコードを使用する場合は不要です。

例: シンプル アップロード

Play ゲームサービスの Publishing API でのシンプル アップロード リクエストの使用例を次に示します。

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/png
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

PNG data

リクエストが成功すると、HTTP ステータス コード 200 OK がメタデータとともにサーバーから返されます。次に例を示します。

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

マルチパート アップロード

アップロードするデータと一緒にメタデータを送信する場合は、単一の multipart/related リクエストを作成できます。この方法は、送信するデータが小さく、接続が失敗したときはデータ全体を再アップロードできる場合に適しています。

マルチパート アップロードを使用するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=multipart を追加します。次に例を示します。

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart

マルチパート アップロード リクエストの作成時に使用する最上位の HTTP ヘッダーの内容は次のとおりです。

Content-Type: multipart/related に設定し、リクエストのパートの識別に使用するバウンダリ文字列を追加します。

Content-Length: リクエスト本文の総バイト数に設定します。リクエストのメディア部分は、このアップロード方法で指定したファイルサイズの上限より小さくする必要があります。

リクエスト本文の形式は multipart/related コンテンツ タイプ RFC2387 として設定され、厳密に 2 つのパートで構成されます。パートはバウンダリ文字列で識別され、最後のバウンダリ文字列の後に 2 つのハイフンが続きます。

マルチパート リクエストの各パートには、追加の Content-Type ヘッダーが必要です。

  • メタデータ パート: 最初に配置する必要があります。Content-Type は、使用可能なメタデータ形式のいずれかと一致しなければなりません。

  • メディアパート: 2 番目に配置する必要があります。Content-Type は、アップロード方法で使用可能なメディア MIME タイプのいずれかと一致しなければなりません。

各アップロード方法で使用可能なメディア MIME タイプの一覧とアップロード ファイルのサイズの上限については、Publishing API のリファレンスをご覧ください。

例: マルチパート アップロード

Play ゲームサービスの Publishing API でのマルチパート アップロード リクエストの例を次に示します。

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Type: multipart/related; boundary=foo_bar_baz
Content-Length: number_of_bytes_in_entire_request_body

--foo_bar_baz
Content-Type: application/json; charset=UTF-8

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

--foo_bar_baz
Content-Type: image/png

PNG data
--foo_bar_baz--

リクエストが成功すると、HTTP ステータス コード 200 OK がメタデータとともにサーバーから返されます。

HTTP/1.1 200
Content-Type: application/json

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

再開可能アップロード

データファイルのアップロードの信頼性を向上させるには、再開可能アップロード プロトコルを使用します。このプロトコルを使用すると、通信障害でデータの送信が中断されても、後でアップロード操作を再開できます。この方法は、大容量のファイルを転送するときや、ネットワークの中断やその他の送信エラーが起こる可能性が高いとき(たとえばモバイル クライアント アプリからアップロードするとき)に、特に役立ちます。また、ネットワーク障害が発生した場合に大容量のファイルのアップロードを最初からやり直す必要がなくなり、帯域幅の使用を削減できます。

再開可能アップロードを使用する手順は次のとおりです。

  1. 再開可能セッションを開始します。メタデータ(存在する場合)を含むアップロード URI への最初のリクエストを送信します。

  2. 再開可能セッション URI を保存します。最初のリクエストのレスポンスで返されたセッション URI を保存します。この URI はセッションの後続のリクエストで使用します。ファイルをアップロードします。

  3. 再開可能セッション URI にメディア ファイルを送信します。

また、再開可能アップロードを使用するアプリには、中断されたアップロードを再開するためのコードも必要です。アップロードが中断された場合は、正常に受信されたデータ量を確認し、中断されたポイントからアップロードを再開します。

再開可能セッションを開始する

再開可能アップロードを開始するには、アップロード方法の /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=resumable を追加します。次に例を示します。

POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable

この最初のリクエストでは、本文は空またはメタデータのみのいずれかです。アップロードするファイルの実際の内容は後続のリクエストで転送します。

最初のリクエストでは次の HTTP ヘッダーを使用します。

  • X-Upload-Content-Type: 後続のリクエストで転送するアップロード データのメディア MIME タイプに設定します。

  • X-Upload-Content-Length: 後続のリクエストで転送するアップロード データのバイト数に設定します。このリクエストの時点でデータの長さが不明な場合、このヘッダーは省略できます。

  • Content-Type(メタデータを送信する場合): メタデータのデータ型に合わせて設定します。

  • Content-Length: この最初のリクエストの本文で送信するバイト数に設定します。チャンク形式の転送エンコードを使用する場合は必要ありません。

各アップロード方法で使用可能なメディア MIME タイプの一覧とアップロード ファイルのサイズの上限については、Publishing API のリファレンスをご覧ください。

例: 再開可能セッション開始リクエスト

Play ゲームサービスの Publishing API で再開可能セッションを開始する方法の例を次に示します。

POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer your_auth_token
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/png
X-Upload-Content-Length: 2000000

{
  "kind": "gamesConfiguration#imageConfiguration",
  "url": string,
  "resourceId": string,
  "imageType": string
}

次に、レスポンスの処理方法について説明します。

再開可能セッション URI を保存する

セッション開始リクエストが成功すると、API サーバーはレスポンスとして HTTP ステータス コード 200 OK を返します。また、再開可能セッション URI を示す Location ヘッダーも返します。下記の例の Location ヘッダーには、このセッションで使用する一意のアップロード ID を示す upload_id クエリ パラメータ部分が含まれています。

例: 再開可能セッション開始リクエストのレスポンス

ステップ 1 のリクエストに対するレスポンスは次のとおりです。

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

上記のレスポンス例に示されている Location ヘッダーの値は、実際にファイルをアップロードするとき、またはアップロード ステータスをクエリするときに、HTTP エンドポイントとして使用するセッション URI です。

後続のリクエストで使用できるように、セッション URI をコピーして保存します。

ファイルをアップロードする

ファイルをアップロードするには、前のステップで取得したアップロード URI に PUT リクエストを送信します。アップロード リクエストの形式は次のとおりです。

PUT session_uri

再開可能なファイル アップロードのリクエストを作成するときに使用する HTTP ヘッダーには、Content-Length を含めます。この値は、このリクエストでアップロードするバイト数(通常はアップロード ファイルのサイズ)に設定します。

例: 再開可能なファイル アップロード リクエスト

この例で 2,000,000 バイトの PNG ファイル全体をアップロードする再開可能なリクエストは次のとおりです。

PUT https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/png

bytes 0-1999999

リクエストが成功すると、サーバーは HTTP 201 Created とともに、このリソースに関連付けられているメタデータをレスポンスとして返します。再開可能セッションの最初のリクエストが既存のリソースを更新する PUT だった場合、成功時のレスポンスでは、200 OK とともに、このリソースに関連付けられているメタデータが返されます。

アップロード リクエストが中断された場合や、サーバーから HTTP 503 Service Unavailable などの 5xx レスポンスが返された場合は、中断されたアップロードを再開するに記載された手順を実施してください。


チャンクでファイルをアップロードする

再開可能アップロードでは、ファイルをチャンクに分割し、一連のリクエストを送信して各チャンクを順番にアップロードすることもできます。しかし、リクエスト数の増加に伴ってパフォーマンス コストがかかるため、このアプローチはおすすめしません。また、通常は不要です。ただし、1 つのリクエストで転送するデータの量を減らすために、チャンクの使用が必要になることもあります。Google App Engine リクエストの一部のクラスのように、リクエストごとに固定の時間制限がある場合は、この方法が役立ちます。また、アップロードの進行状況がデフォルトでサポートされていない従来のブラウザで、アップロードの進行状況を提供することもできます。

データをチャンクでアップロードする場合は、ファイル全体のアップロードに必要な Content-Length ヘッダーに加えて、Content-Range ヘッダーも必要です。

  • Content-Length: チャンクサイズに設定します。最後のリクエストではチャンクサイズ未満の値にすることもできます。

  • Content-Range: ファイルの何バイト目から何バイト目までをアップロードするかを設定します。たとえば、Content-Range: bytes 0-524287/2000000 は、2,000,000 バイトのファイルで先頭の 524,288 バイト(256 x 1,024 x 2)をアップロードすることを意味します。

例: チャンク形式ファイルの再開可能アップロード リクエスト

最初の 524,288 バイトを送信するリクエストは次のようになります。

PUT {session_uri} HTTP/1.1
Host: www.googleapis.com
Content-Length: 524288
Content-Type: image/png
Content-Range: bytes 0-524287/2000000

bytes 0-524288

リクエストが成功すると、サーバーは 308 Resume Incomplete とともに、その時点までに格納された総バイト数を示す Range ヘッダーをレスポンスとして返します。

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-524287

Range ヘッダーで返された上限値を使用して、次のチャンクの開始位置を決定します。ファイル全体のアップロードが完了するまで、ファイルのチャンクごとに PUT を続けます。

チャンクの PUT リクエストが中断された場合や、サーバーから HTTP 503 Service Unavailable などの 5xx レスポンスが返された場合は、中断されたアップロードを再開するに記載された手順を実施してください。ただし、ファイルの残りをアップロードするのではなく、中断した位置からチャンクのアップロードを続行します。

注意事項:

  • 次のチャンクの開始位置を決定する際は、必ずレスポンスの Range ヘッダーを使用してください。前のリクエストで送信したバイトがすべてサーバーで受信されたとは限りません。

  • 各アップロード URI には有限の存続期間があり、使用しなければ 1 日程度で有効期限が切れます。このため、アップロード URI を取得したら早急に再開可能アップロードを開始し、中断が発生した場合はすぐにアップロードを再開することをおすすめします。

  • 有効期限が切れたアップロード セッション ID を使用してリクエストを送信すると、サーバーからステータス コード 404 Not Found が返されます。アップロード セッションで回復不能なエラーが発生すると、サーバーからステータス コード 410 Gone が返されます。これらの場合は、再開可能アップロードを新たに開始して新しいアップロード URI を取得し、新しいエンドポイントを使用してアップロードを最初からやり直す必要があります。

ファイル全体のアップロードが完了すると、サーバーは HTTP 201 Created とともに、このリソースに関連付けられているメタデータをレスポンスとして返します。このリクエストが新しいエンティティの作成ではなく既存のエンティティの更新を行うものであった場合、完了したアップロードの HTTP レスポンス コードは 200 OK になります。


中断されたアップロードを再開する

レスポンスを受信する前にアップロード リクエストが終了した場合や、サーバーから HTTP 503 Service Unavailable レスポンスが返された場合は、中断されたアップロードを再開する必要があります。中断されたアップロードを再開する手順は次のとおりです。

  1. ステータスをリクエストします。空の PUT リクエストをアップロード URI に送信して、アップロードの現在のステータスをクエリします。このリクエストの HTTP ヘッダーには、ファイルの現在の位置が不明であることを示す Content-Range ヘッダーを含める必要があります。たとえば、ファイルの合計サイズが 2,000,000 バイトの場合は、Content-Range*/2000000 に設定します。ファイル全体のサイズがわからない場合は、Content-Range を */* に設定します。

  2. アップロードされたバイト数を取得します。ステータス クエリからのレスポンスを処理します。サーバーはレスポンスの Range ヘッダーを使用して、その時点までに何バイト受信したかを示します。たとえば、Range ヘッダーが 0-299999 の場合、ファイルの先頭から 300,000 バイトが受信されたことがわかります。

  3. 残りのデータをアップロードします。リクエストの再開ポイントがわかったので、最後に残りのデータまたは現在のチャンクを送信します。どちらの場合も、残りのデータを独立したチャンクとして扱う必要があります。つまり、アップロードを再開するときに Content-Range ヘッダーを送信する必要があります。

例: 中断されたアップロードを再開する

  1. アップロード ステータスをリクエストします。次のリクエストでは、Content-Range ヘッダーを使用して、2,000,000 バイトのファイルで現在の位置が不明であることを示しています。

    PUT {session_uri} HTTP/1.1
    Content-Length: 0
    Content-Range: bytes */2000000
    
  2. レスポンスから、これまでにアップロードされたバイト数を抽出します。サーバーのレスポンスの Range ヘッダーは、これまでにファイルの先頭の 43 バイトを受信したことを示しています。Range ヘッダーの上限値を使用して、再開可能アップロードを開始する位置を決定します。

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42
  1. 中断した位置からアップロードを再開します。次のリクエストでは、アップロードが再開されて、ファイルのバイト位置 43 以降の残りのバイトが送信されます。
PUT {session_uri} HTTP/1.1
Content-Length: 1999957
Content-Range: bytes 43-1999999/2000000

bytes 43-1999999

ベスト プラクティス

メディアをアップロードする場合は、エラー処理に関するおすすめの方法が参考になります。

  • 接続の中断や次のような 5xx エラーが原因で失敗したアップロードは、再開または再試行してください。

    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • アップロード リクエストを再開または再試行したときに 5xx サーバーエラーが返された場合は、指数バックオフ戦略を使用します。この種のエラーは、サーバーが過負荷になっている場合に発生することがあります。指数バックオフは、リクエスト量またはネットワーク トラフィックが多い時間帯に、この種の問題を緩和するために役立ちます。

  • その他の種類のリクエストは指数バックオフでは処理できませんが、多くのリクエストは再試行が可能です。リクエストを再試行する際に、再試行回数を制限します。たとえば、コードを使用して、再試行回数を 10 回に制限し、それを超えたらエラーを出力するようにします。

  • 再開可能アップロードの実行中に 404 Not Found または 410 Gone エラーが発生した場合は、ファイル全体のアップロードを最初からやり直します。

指数バックオフ

指数バックオフはネットワーク アプリケーションで使用される標準的なエラー処理戦略で、失敗したリクエストをクライアントが再試行する際に、失敗するたびに次の再試行までの待機時間を増やしていく方法です。指数バックオフは、リクエスト量またはネットワーク トラフィックが多いためにサーバーがエラーを返す場合のエラー処理に適しています。一方、認証情報が無効なエラーやファイルが見つからないエラーなど、ネットワーク量または応答時間と無関係なエラーの処理には適していません。

指数バックオフを適切に使用すると、帯域幅の使用の効率を高め、正常なレスポンスを受け取るために必要なリクエストの数を減らし、同時実行環境におけるリクエストのスループットを最大化することができます。

単純な指数バックオフを実装するフローを次に示します。

  1. API にリクエストを送信します。
  2. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  3. 1 秒 + random_number_milliseconds の間待機してから、リクエストを再試行します。
  4. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  5. 2 秒 + random_number_milliseconds の間待機してから、リクエストを再試行します。
  6. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  7. 4 秒 + random_number_milliseconds の間待機してから、リクエストを再試行します。
  8. リクエストの再試行が必要であることを示す HTTP 503 response を受信します。
  9. 8 秒 + random_number_milliseconds の間待機してから、リクエストを再試行します。
  10. リクエストの再試行が必要であることを示す HTTP 503 response を受信します。
  11. 16 秒 + random_number_milliseconds の間待機してから、リクエストを再試行します。
  12. 処理を停止します。エラーを報告または記録します。

上記のリストで、random_number_milliseconds は 1,000 以下のランダムなミリ秒数です。これが必要なのは、短いランダムな遅延時間を挿入することで負荷をより均等に分散し、サーバーの暴走を防ぐためです。random_number_milliseconds の値は、個々の待機の後で再定義する必要があります。

上記のアルゴリズムは、n が 5 に達したら停止するように設定されています。この上限によって、クライアントが無限に再試行を繰り返すことを防ぎます。総遅延時間が約 32 秒に達すると、リクエストは「回復不能なエラー」と判断されます。再試行の最大回数を増やすこともできます(特に、長時間かかるアップロードの場合など)。ただし、再試行の遅延時間には必ず合理的な上限(たとえば 1 分未満)を設定してください。

API クライアント ライブラリ ガイド