UnityとAWS AppSyncでHelloWorld

[AWS & Game Advent Calendar 2020](https://qiita.com/advent-calendar/2020/aws-game) の4日目の記事になります。

#はじめに
PC/モバイルゲームのバックエンドを担うAPIサーバーはいわゆるweb3層アプリケーションで構築されることが多いと思います。
web3層アプリケーションの構築においてはアプリケーションのロジック部分の開発の他にサーバーの構築・管理が必要となります。
最近ではそのサーバーの構築・管理のコストを下げてロジック部分の開発に集中するための手段としてサーバーレスアーキテクチャが採用される事例も増えています。
このサーバーレスアーキテクチャにおいてはAmazon API Gateway + AWS Lambda + Amazon Dynamo DBといった構成が中心となる場合が多いと思います。
![ServerlessArchitecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/47839dc3-e992-9f15-8f75-134828168c80.png)
本記事ではこのAWS Lambdaを中心としたサーバーレスアーキテクチャではなくAWS AppSyncをサーバーレスなゲームのバックエンドとして利用することを想定し、手始めとしてUnityとAWS AppSyncでHelloWorldを試します。
![AppSyncArchitecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/25672db8-4038-dd2a-9711-ce33e3b240cf.png)
※本記事ではHelloWorldとなるため上図の赤枠部分のみの実装となります。予めご了承ください。

#AWS AppSync
そもそもとしてAWS AppSyncとは何か、という話になりますが、[AWS AppSync](https://aws.amazon.com/jp/appsync/)は[GraphQL](https://graphql.org/)のマネージドサービスです。
GraphQLの詳細な説明は割愛しますが、ゲーム開発においても主に以下のメリットを享受できるのではないかと考えられます。

* 一度のリクエストでクライアントが必要とする全てのデータを過不足なく取得する(複数のデータを取得する必要がある場合でもリクエストを分ける必要がなく効率的)
* GraphQLスキーマによるクライアント-サーバー間の強力な型付け
* データの取得・更新だけでなくGraphQLのSubscriptionsによって、WebSocketを介したデータ更新のリアルタイムでのプッシュが可能(チャット機能などの実装)

AWS AppSyncは前述の通りGraphQLのマネージドサービスとなっておりGraphQL APIサーバーの構築やインフラの管理は不要となるため、上記のようなGraphQLのメリットを得ることをより容易にしてくれます。
また当然ながら他のAWSサービスとの統合も容易にできるため、AWS AppSyncからAWS LambdaやAmazon DynamoDBなどのサーバーレスサービスを組み合わせてフルサーバーレスなバックエンドを構築することが可能です。

#実装

##AWS AppSyncの設定
AWSコンソールからAWS AppSyncを開き、「APIを作成」をクリックします。
以下のようなページが開かれます。今回は「一から構築」を選び、右横の「開始」ボタンをクリックします。
![スクリーンショット1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/5a1a883a-4867-a58d-b21b-4954737f0459.png)
「リソースを作成」という画面に遷移します。API名には任意の文字列を入力してください。ここではUnityAppSyncSampleとしています。
API名を入力したら「作成」ボタンをクリックします。
![スクリーンショット2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/52ad0ad5-ea32-68af-1032-6130c2d600f6.png)
APIが作成されると以下の画面に遷移します。スキーマを作成するため、左サイドメニューにある「スキーマ」をクリックしスキーマ画面を開きます。
![スクリーンショット3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/b746acc4-ad3a-7ef1-25e9-fe0c68b9817a.png)
スキーマの入力欄に対して以下の内容を入力し「スキーマの保存」をクリックします。

```
type Query {
	text: String
}

schema {
	query: Query
}
```
![スクリーンショット4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/32b0de9c-f4f0-ece5-7343-b4dcead995ea.png)
スキーマの保存ができたら次はデータソースの作成を行います。左サイドメニューにある「データソース」をクリックしデータソース画面を開きます。
以下の画面が開かれるので右側の「データソースを作成」ボタンをクリックします。
![スクリーンショット5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/611f9317-eb1f-617b-ac94-c1c3d92f6cf8.png)
データソース名には任意の文字列を入力してください。ここではUnityAppSyncSampleDataSourceとしています。データソースタイプは「なし」を選択します。
データソース名、データソースタイプの入力が完了したら右下の「作成」をクリックします。
![スクリーンショット6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/7b44fee4-a8f6-fb52-ac74-550182f2ebc6.png)
データソースの作成が完了したら、次はResolverの設定を行います。左サイドメニューにある「スキーマ」をクリックしスキーマ画面を開きます。
右側の「Resolvers」のQueryに「text:String」が表示されていることを確認し、右側の「アタッチ」ボタンをクリックします。
![スクリーンショット7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/827ac496-4afb-2426-ae7b-5385e43af940.png)
「新しいリゾルバーを作成」という画面に遷移します。
「Queryのリゾルバー」で選択するデータソース名では先ほど作成したデータソース(UnityAppSyncSampleDataSource)を選択します。
リクエストマッピングテンプレートには以下を入力します。

```
{
    "version": "2017-02-28",
    "payload": {}
}
```
レスポンスマッピングテンプレートには任意の文字列を入力します。今回は「Hello World」としています。
これらの入力が完了したら「リゾルバーを保存」ボタンをクリックします。
![スクリーンショット8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/114bb4d2-a369-20d7-d1a7-8ca6b42c40fb.png)
リゾルバーの保存が完了したら左サイドメニューにある「設定」をクリックし設定画面を開きます。
![スクリーンショット9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/1158b069-e52d-597b-94b7-39a09539398a.png)
「API Details」にある「API URL」とプライマリ認証モードの「API KEY」についてはこの後のUnity側の実装で使うので参照できるようにしておきます。

#Unity側の実装
UnityProjectを作成します。

AWS AppSyncにアクセスするにはGraphQLのクライアントが必要となります。
GraphQLのクライアントが含まれるパッケージをインストールするためにNuGetを使いたいので、まずNuGetForUnityをインストールします。
https://github.com/GlitchEnzo/NuGetForUnity/releases
こちらから「NuGetForUnity.X.Y.Z.unitypackage」をダウンロードし、unitypackageをUnityProjectにインポートします。

NuGetForUnityがインポートできたらNuGetがメニューバーに追加されるので、「Manage NuGet Package」をクリックし、GraphQLで検索します。
![スクリーンショット10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/d540ca48-eca6-4e3f-6287-8b6e5ca2e9f1.png)
![スクリーンショット11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/53820e71-48aa-b54d-9602-64d97f32dcfb.png)

検索結果にはたくさんのGraphQL関連のパッケージが表示されますが、今回はHelloWorldのみの実装に必要な以下のパッケージをインストールします。

* GraphQL.Client
* GraphQL.Client.Serializer.Newtonsoft

上記パッケージのインストールが完了したらAssets以下にHelloWorldButtonというC# Scriptを作成し、以下のコードをコピー&ペーストします。

```
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using GraphQL.Client.Http;
using GraphQL.Client.Abstractions;
using GraphQL.Client.Serializer.Newtonsoft;
public class HelloWorldButton : MonoBehaviour
{
    const string API_URL = "";
    const string API_KEY = "";

    class HelloWorldResponse
    {
        public string text { get; set; }
    }
    public async void OnClick()
    {
        var graphQLClient = new GraphQLHttpClient(API_URL, new NewtonsoftJsonSerializer());
        graphQLClient.HttpClient.DefaultRequestHeaders.Add("x-api-key", API_KEY);

        var query = "query MyQuery { text }";
        var graphQLResponse = await graphQLClient.SendQueryAsync<HelloWorldResponse>(query, CancellationToken.None);
        Debug.Log(graphQLResponse.Data.text);
    }
}
```
コード内ではAPI_URL, API_KEYという定数が空文字となっていますが、これらにはそれぞれAWS AppSyncの設定画面で表示されていた「API URL」「API KEY」をコピー&ペーストします。

コードを保存したらUnity内の「Hierarchy」からCanvasを追加し、そのCanvas内にButtonを追加します。追加したボタンに先ほど作成したHelloWorldButtonをアタッチします。
![スクリーンショット12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/229a88d3-4013-3af3-d895-106dd1411799.png)
Buttonの設定からOnClickイベントの設定を行います。ObjectにはCanvas上のButtonオブジェクトをドラッグ&ドロップします。
![スクリーンショット13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/c4fb9c8d-c07d-24e4-b2f4-e21441067376.png)
NoFunctionとなっている部分では「HelloWorldButton」から「OnClick」を選択します。
![スクリーンショット14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/46ff41ca-9d6c-1ac5-ef6a-997b31a14fde.png)
ここまで設定できたら再生ボタンをクリックしゲームを実行し、HelloWorldボタンをクリックします。
そうするとコンソールにAWS AppSyncからのレスポンスである「Hello World」が表示されることが確認できます。
![スクリーンショット15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19106/ac01d2a8-2354-47a9-bb04-1c0d109853e9.png)

#おわりに
今回はUnityとAWS AppSyncでHelloWorldを実施するのみとなりましたが、今後もゲームのバックエンドにGraphQLを用いる事例やAWS AppSyncと他のサービスを統合するサンプルについてまとめていきたいと思います。
特にAWS AppSyncでのユーザー認証の実装として[Amazon Cognito](https://aws.amazon.com/jp/cognito/)を統合することはAWS AppSyncを実用化していく上で有用な事例となりそうなので、次回はその辺りをまとめたいと思います。

実際にゲームのバックエンドでGraphQLを使われた方やあるいはGraphQLについて知見をお持ちの方はご意見いただけますと幸いです。

(免責) 本記事の内容はあくまでも個人の意見であり、所属する企業や団体とは関係がございません。

#参考
Serverless backendformobilegame and_aws-appsync_gamingtechnight-2
https://www.slideshare.net/AmazonWebServicesJapan/serverless-backendformobilegame-andawsappsyncgamingtechnight2

AWS AppSyncを使ってHello Worldする
https://www.injpok.tokyo/posts/2018/08/helloappsync/