最終更新:
orika_ex_miyako 2026年05月20日(水) 10:20:44履歴
・CloudScript を呼びたい ・サーバー側でデータを処理したい ・処理した情報を Json で受け取りたい ・API 通信を共通化したい
という場面が出てきます。
ですがそれらを調べていくと当然ながら、新しい単語や処理にぶつかります。
・API とは? ・リクエストって? ・レスポンスって? ・JsonConvert.DeserializeObject って何をしているの?
こういった部分で止まりやすいです。
この記事では、「Unity から PlayFab CloudScript を呼び、JsonConvert でデータを復元する流れ」を、初心者向けにまとめます。
API とは Application Programming Interface の略語です。
異なるソフトウェアやアプリ同士をつなぐ「橋渡し役」や「窓口」としての機能を API と呼んでいます。
Unity の場合に置き換えると
1.Unity → サーバーへ処理をお願いする 2.サーバー → Unity へ処理の結果を返す
このときの 「1.Unity → サーバー」、「2.サーバー → Unity」の橋渡し役となるのが API です。
例えば、
現在のサーバー時間をください
と Unity 側からお願いすると、サーバーから
2026/05/13 12:34:56
というように結果が返ってきます。
これが API の機能です。
実際に利用する場合には、API 通信、あるいは API 連携と言います。
API 通信には必ず
1.リクエスト(Request) 2.レスポンス(Response)
この2つがセットであります。
先ほどの Unity とサーバーの関係に置き換えると、以下のようになります。
1.Unity → サーバーへ処理をお願いする(リクエスト) 2.サーバー → Unity へ処理の結果を返す(レスポンス)
Unity → サーバーへ送る情報です。このとき、サーバー側で利用する情報をパラメータとして一緒に送信することができます。
送信できるパラメータは、サーバー側で設定されている情報と一致する必要があります。考え方としてはメソッドの引数と同じです。
例えば、サーバー側に、現在のサーバー時刻を教えてもらいたい場合、リクエストを作成して送信します。
これは C# で置き換えた場合、サーバー時刻を戻り値で戻せるメソッドを実行するのと同じ形です。
処理がクライアント側で終わるのか、サーバーを経由するかの違いだけです。
このとき、サーバー側は Unity に対してリクエストに付随するパラメータを要求できます。
これも C# で置き換えた場合、メソッドを実行する際に一緒に書きこむ引数の情報と同じ形です。
今回のケースでは「PlayFab にログインしているユーザーの情報」をセットしてほしい、というパラメータがついています。
{
"sessionTicket": "xxxxx"
}
このように、「ログイン済ユーザーですよ」という情報をセットしてリクエストを送信するようにします。
つまり、サーバー側に用意してあるメソッドを実行するイメージです。
"sessionTicket" の部分があらかじめ、サーバー側から要求されているパラメータの名前(Key) です。これにはデータ型も一緒に定義されています(ここでは見れません)
それに対して : の右側に情報(Value) を書きこみます。sessionTicket のデータ型が string になっているので、情報も文字列として認識されるように "" で囲んでいます。
サーバー → Unity へ返す情報です。サーバー内で処理した結果を返します。
先ほどのリクエストでは「サーバー時刻を教えて欲しい = 返して欲しい」という処理になっていましたので
{
"status": 0,
"data": {
"serverTime": "2026-05-13T12:34:56"
}
}
このように Json の形でデータが Unity に返ってきます。
C# に置き換えると、メソッドを実行した結果の戻り値と同じ形です。
Unity 側ではこのレスポンスの情報を元にクラスに復元します。そうすることで Unity 内で利用できるデータになります。
ここで一旦 Web 関係の API でよく利用される GET と POST について解説します。
どちらもリクエストに分類されるものであり、実行する内容に合わせたパラメータをつけてサーバーに送信します。
サーバーから「データを取得したい」時に使うリクエストです。
例:
・サーバー時間取得 ・ユーザー情報取得 ・ランキング取得
など。
つまり読み取り専用の情報です。サーバー内の情報は更新されません。
サーバーに「データを送信したい(サーバー内の情報を新規作成や更新したい)」かつ、「その後のデータを取得したい」時に使うリクエストです。
例:
チーム編成更新 アイテム購入 セーブ
GET とは異なり、サーバー内の情報が更新されます。
以上のことから、PlayFab の CloudScript は、関数名 + 引数を使い、更新用のデータをサーバーに送って実行するため、イメージとしては POST に近いです。
PlayFab や CloudScript を実行したサーバーから Unity にレスポンスされる情報は Json データです。
これは文字列の情報になっていますので、そのままではクラスの情報 = Unity でそのまま使える情報にはなっていません。
よって、取得した Json データを Unity のクラスとして復元し、利用できる状態にする必要があります。
今回サーバーからのレスポンスデータの復元用には Newtonsoft.Json を利用します。
こちらは Unity では非常によく使われる Json ライブラリです。こちらに含まれている JsonConvert クラスを利用します。
こちらの記事を参考に Unity に導入してください。
Qiita @kazuma_f 様
[Unity]Newtonsoft.Jsonの基本的な使い方
https://qiita.com/kazuma_f/items/55a0b7ff628ab596e...
DeserializeObject(デシリアライズ・オブジェクト) メソッドは JsonConvert クラスに用意されているメソッドです。
引数に Json 形式の文字列を指定することで、それを<T> の型引数で指定したクラスに変換します。
Deserialize とは、文字列やバイナリ形式のデータをオブジェクト(C# のクラス)として復元することです。
Newtonsoft 公式ドキュメント
JsonConvert.DeserializeObject Method
https://www.newtonsoft.com/json/help/html/Overload...
var result = JsonConvert.DeserializeObject<PlayerData>(json);
あるいは型を指定して記述します。
PlayerData result = JsonConvert.DeserializeObject<PlayerData>(json);
この場合であれば、json 変数が Json 形式の文字列であり、それを PlayerData クラスへ変換を行っています。
Json データの例ですが、例えばサーバーからのレスポンスデータが下記のような Json 情報だとします。
{
"userName": "Player",
"coin": 1000
}
こちらの情報が返ってきた場合、同じパラメータの変数を持つクラスを用意しておき、そちらに文字列を型の情報として復元します。
用意するクラスの注意点は3つあります。
1.MonoBehaviour の継承はしないでください。 2.[System.Serializable] 属性を必ず付与してください。 3.変数名は必ずレスポンスデータのパラメータと同じ名前にしてください(大文字小文字も区別されます)。変数の並び順は関係ありません。
用意しておくクラス
[System.Serializable] ← 忘れずに
public class PlayerData {
public string userName; ← レスポンスデータのパラメータと同じ名前の変数
public int coin;
}
事前にクラスを用意しておいて、サーバーにリクエストを送信し、レスポンスデータを受け取ります。
受け取った Json データを PlayerData クラスに復元して Unity で利用できる状態にします。
<復元(デシリアライズ)>
PlayerData playerData = JsonConvert.DeserializeObject<PlayerData>(json);
すると、playerData.userName の変数には、"Player" の文字列が入ります。
また、playerData.coin の変数には 1000 の数値が入ります。ポイントはクラスの型に見合った情報として代入されて復元される点です。
coin 変数が int 型であるため、Json の文字列が数値として復元・認識される状態になります。
Json のデシリアライズについては多くの記事がありますので、目を通しておくとよいでしょう。
Freelance Chance 様
【C#】JSON配列をデシリアライズする方法とエラー対策
https://freelancechance.tech/csharp-json-deseriali...
Qiita @TsuyoshiUshio 様
C# の Json.NET を理解する
https://qiita.com/TsuyoshiUshio@github/items/4f497...
CloudScript を実行したり、レスポンスデータとして受け取る情報は様々になります。
そのため、その都度、実行用のメソッドを制作していくと膨大な数になってしまいます。
そこで今回の構成ではこちらを使います。
[System.Serializable]
public class CloudScriptResponse<T> {
public int status;
public string errorMessage;
public T data;
}
public T data をジェネリック型として定義しているのは、
先ほどもお伝えしたように CloudScript によって、返したい data の内容が変わるためです。
例えば、サーバー時間取得なら serverTime だけ返せばいいでしょう。
しかし、チーム編成更新ならば、TeamData や CharaList など、複数の異なる Json データを返したい(Unity 側でもらいたい)です。
このようにデータの形が違うからといって、送信(リクエスト)・受信用(レスポンス)のメソッドを作っていくと大変です。
そこで今回はこれを一元化し、CloudScriptResponse<T> として汎用化し、共通処理として利用できるようにしています。
API を実行するためのメソッドも一元化します。
UniTask を利用し、サーバーとのやりとりを非同期処理で行う形です。
public static async UniTask<CloudScriptResponse<T>> CallCloudScriptFunction<T>(string functionName, Dictionary<string, object> parameters = null) {
}
第1引数である functionName は、CloudScript 側の関数名です。
例えば、"ServerNowTime" という処理をサーバー側で用意してあるなら、ここで文字列として指定することで、ServerNowTime 関数を実行することができます。
第2引数である parameters は CloudScript へ送る引数情報です。Dictionary<string, object> を使っています。
これはつまり、引数の情報を書き換えるだけで API 通信をするためには常にこの処理を1行だけ書けば実行できるという設計で動いています。
よって API が増えたとしても通信用のメソッドを増やす必要はなく、API 用の適切なリクエストパラメータを用意すれば、あとは同じ処理で API 通信が行えるようになっています。
最初に API へのリクエストのためのリクエストパラメータを作成します。
string functionName = "ServerNowTime"; // サーバーに用意されている API(関数名)
Dictionary<string, object> functionParameter = new() { // サーバーに送信する引数(パラメータ)
{ "sessionTicket", LoginManager.sessionTicket } // Dictionary なので、API に応じて複数の情報を指定できる
};
続いて、サーバーにリクエストを送信(API 処理を実行)します。送信する情報がリクエストパラメータになります。
var response = await PlayFabAPIManager.CallCloudScriptFunction<PlayFabPlayerDataResult>(functionName, functionParameter);
これで Unity → PlayFab → CloudScript へ通信されます。
正常に処理が行われると、response 変数にレスポンスパラメータが代入されます。
レスポンスで取得した response 変数の data は T 型であり、復元が終了している状態です。
そのため、任意のクラス変数に利用することが可能です。
DateTime serverTime = response.data.serverTime;
これで API を利用し、Unity 側でサーバー時間を取得できます。
サーバーとの処理には時間がかかりますので、非同期処理を利用して通信の間、処理を一時停止させておきます。
通信終了後、レスポンスデータに問題がないかをチェックしてから、処理を再開していきます。
public DateTime currentLocalTime;
public static async UniTask SetCurrentLocalTimeFromServerTime() {
// リクエストパラメータを作成
string functionName = "ServerNowTime";
Dictionary<string, object> functionParameter = new() {
{ "sessionTicket", LoginManager.sessionTicket }
};
// API 通信 → リクエストパラメータを使ってリクエストを送信。await を利用して API 処理が終了するまで待機
var response = await PlayFabAPIManager.CallCloudScriptFunction<PlayFabPlayerDataResult>(functionName, functionParameter);
// API 通信処理終了後、レスポンスデータが戻ってきているので、その中身があるか(復元されているか)チェック
if (response != null) {
// 問題なければ復元されている情報を代入
DateTime serverTime = response.data.serverTime;
currentLocalTime = serverTime;
// 直接入れても問題ない
currentLocalTime = response.data.serverTime;
Debug.Log($"[サーバー時間取得] currentLocalTime : {currentLocalTime}");
}
}
次は TeamEdit のような、データを更新するための引数のある API の説明をします。
API 内容としては、チーム編成更新です。
ここではリクエストパラメータとして
sessionTicket stageType charaNos
の3つを送信するとします。そして、このデータをサーバー側に登録し、更新後の最新データをレスポンスデータとして受け取る流れになります。
先ほどと同じでリクエストのためのリクエストパラメータを作成します。
API として TeamEdit が用意してある前提です。
string functionName = "TeamEdit";
Dictionary<string, object> functionParameter = new() {
{ "sessionTicket", LoginManager.sessionTicket },
{ "stageType", stageType },
{ "charaNos", charaNos }
};
API を実行する処理です。
この処理は共通化してあるので、先ほどとまったく同じ処理を実行しています。
つまり、リクエストパラメータのみ作れば、毎回同じ処理を実行するだけで API が実行可能な設計です。
var response = await PlayFabAPIManager.CallCloudScriptFunction<PlayFabPlayerDataResult>(functionName, functionParameter);
最後にレスポンスデータの受け取り処理です。
こちらも先ほどと同様で、data 変数は Unity で利用できるクラス情報に復元済です。
TeamData teamData = response.data.teamData; List<CharaData> charaList = response.data.charaList;
CloudScript は API ごとにレスポンス内容が違います。しかし毎回別クラスを作ると管理が大変です。
そこで PlayFabPlayerDataResult クラスを用意し、必要になる可能性があるレスポンスデータの情報をまとめて管理しています。
復元時には、PlayFabPlayerDataResult 内に Json 情報がクラスとして復元されますので、
あとは Unity 側で利用したいクラスにデータを代入する形で利用が可能です。
JsonConvert は JSON のキー名と C# の変数名を一致させて復元します。
例えば、
{
"userName": "Player"
}
なら、
public string userName;
へ入ります。
このとき、変数の名前が違うと復元されません。
例えば、
public string name;
これだとレスポンスデータの Json の userName と一致しないため、値が入りません。
Unity のクラス情報そのものを送ろうと考えがちですが、実際には、「通信専用データ」を作ることが非常に重要です。
これがリクエストパラメータです。
特にデータ内に
ReactiveProperty Subject Observable UnityAction
などを含むクラスは JSON 通信に向きません。これらを除外したデータのみのクラスを用意するとよいでしょう。
最終的な流れはこちらです。
Unity ↓ CloudScript 呼び出し ↓ リクエストパラメータ送信 ↓ サーバー処理 ↓ JSON レスポンス返却 ↓ JsonConvert.DeserializeObject ↓ C# クラスへ復元 ↓ Unity 内で利用
Unity + PlayFab CloudScript では下記の処理を理解し、適切に運用することが大切です。
・JsonConvert.DeserializeObject ・共通 API メソッド ・レスポンスクラス ・リクエストパラメータ
設計部分からしっかりと理解すると、開発しやすくなります。
特に CallCloudScriptFunction<T>() のような共通化を行うと、API 追加時の対応、デバッグ、エラーハンドリングが非常に楽になります。
例えば、API が追加されたとしても、専用のメソッドを新しく作る必要がありません。従来の処理をそのまま活用できます。
また 「JSON は単なる通信データ」であり、「ゲーム実行クラスそのものではない」という意識が、サーバー連携ではとても重要になります。
実際に運用可能な4つのクラスをサンプルコードとして提示しておきます。
サンプルのように1つのファイルに書き込んでも問題ありませんし、各クラスを別々のファイルとして用意しても問題ありません。
ここでは using が多く、かつこのクラス内部でのみ利用するという関係上、1つのファイルにまとめて書きこんでいます。
ログの他、エラー時にはゲーム画面にポップアップを開く仕組みになっています。
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using PlayFab;
using PlayFab.CloudScriptModels;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
/// <summary>
/// CloudScript からのレスポンスデータ(Json 受け取り)用
/// </summary>
/// <typeparam name="T"></typeparam>
[Serializable]
public class CloudScriptResponse<T> {
public int status;
public string errorMessage;
public T data;
}
/// <summary>
/// CloudScript からのエラー情報受け取り用
/// 正常に実行できない場合には、status や errorMessage を受け取る
/// </summary>
[Serializable]
public class PlayfabErrorBody {
public int status;
public string errorMessage;
}
/// <summary>
/// Json をクライアント側で運用するための中間クラス
/// 上記 CloudScriptResponse の T 型 data 部分にて利用
/// </summary>
public class PlayFabPlayerDataResult {
public TeamData teamData; // この部分の変数は、すべて自分のプロジェクトの内容で置き換えてください
public List<CharaData> charaList;
public UserCurrency userCurrency = new();
public string userId;
public string userName;
public DateTime serverTime;
public int inventoryEquipMax;
public UserData userData = new();
public List<EquipData> equipList = new();
public List<ItemData> itemList = new();
public List<GemData> gemList = new();
public List<TeamData> teamList = new();
public List<GemAttachData> attachGemList = new();
public List<long> removeAttachGemList = new();
public List<long> removeEquipList = new();
public List<ItemData> rewardItemList = new();
public List<GemData> rewardGemList = new();
public List<EquipData> rewardEquipList = new();
public List<LoginBonusProgressData> openLoginBonusDataList = new(); // 獲得途中のログインボーナス、あるいは未獲得かつ有効期限内のログインボーナスの List
public ItemData loginBonusItem; // 今回取得したアイテム情報(データの更新用では無くポップアップ表示用)
public LoginBonusProgressData loginBonusData; // 更新したログインボーナスデータ
public OpenShopData openShopData; // 開催中のショップ情報
public OpenCoinShopData openCoinShopData; // 商品購入後の最新のコインショップデータ(stockNumを減らした情報)
public ItemData coinShopItem; // 今回購入したアイテム情報(データの更新用では無くポップアップ表示用)
public BattleStageProgressData battleStageProgressData; // バトルステージの進捗データ
public MissionClearData missionData; // ミッションのクリアデータ
public TowerProgressData towerProgressData; // タワーの進捗データ
public DateTime startDateTime; // 放置用
public DateTime nowDateTime;
public List<int> predictItemIdList; // 獲得予定のアイテム ID リスト(放置報酬用。ID 重複なし)
public int remainingDiaCount;
public int remainingTicketCount;
public long predictCoin;
public int latestHouchiStageId;
public List<BattleCharaRaw> playerBattleCharaList = new();
public List<WaveBattleCharaList> enemyWaveBattleCharaList = new();
public BattleOutcomeType battleOutcomeType;
}
/// <summary>
/// CloudScript との API 連携用
/// </summary>
public static class PlayFabAPIManager {
/// <summary>
/// Playfab の CloudScript API 実行メソッド
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="functionName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static async UniTask<CloudScriptResponse<T>> CallCloudScriptFunction<T>(string functionName, Dictionary<string, object> parameters = null) {
ExecuteFunctionRequest request = new() {
Entity = new PlayFab.CloudScriptModels.EntityKey() {
Id = PlayFabSettings.staticPlayer.EntityId,
Type = PlayFabSettings.staticPlayer.EntityType,
},
FunctionName = functionName,
FunctionParameter = parameters,
GeneratePlayStreamEvent = false
};
var response = await PlayFabCloudScriptAPI.ExecuteFunctionAsync(request);
// PlayFab 側でのエラーがある場合
if (response.Error != null) {
//LoginManager.GenerateErrorLog(response.Error);
var match = Regex.Match(response.Error.ErrorMessage, @"\{.*\}");
if (match.Success) {
string json = match.Value;
var parsed = JsonConvert.DeserializeObject<PlayfabErrorBody>(json);
//PopupManager.instance.ShowCommonPopup("エラー", $"エラーコード: {parsed.status}\nメッセージ: {parsed.errorMessage}", "閉じる", null, null);
} else {
//PopupManager.instance.ShowCommonPopup("エラー", response.Error.ErrorMessage, "閉じる", null, null);
}
return default;
}
// 値が正常に取れた場合
if (response?.Result?.FunctionResult != null) {
string json = response.Result.FunctionResult.ToString();
var result = JsonConvert.DeserializeObject<CloudScriptResponse<T>>(json);
// CloudScript の status がエラーの場合
if (result.status != 0) {
// TODO エラー処理
//PopupManager.instance.ShowCommonPopup("エラー", result.errorMessage, "閉じる", null, null);
Debug.Log($"CloudScript : {functionName} がエラーです。");
return default;
}
Debug.Log($"CloudScript : {functionName} が正常に実行されました。");
return result;
} else {
Debug.Log($"CloudScript : {functionName} の応答が null、または形式が正しくありません。");
return default;
}
}
}




コメントをかく