これはドリコム Advent Calendar 2020 の2日目です。
1日目は ogwmtnr さんによる「コロナ禍、リモートワーク、新生児との生活を振り返ってみる」です。 こんにちは。DRIP エンジニアの広井淳貴です。
DRIP は Drecom Invention Project の略称で、ドリコムが発明を産み続けるためのプロジェクトです。
DRIP.png
その中でわたしは「AROW」というプロジェクトで活動しています。AROW では3Dリアルマップの研究開発を行っていて、没入感のある新しいゲーム体験の実現を目指すために現在開発中です。

記事の内容

今回は、SwaggerCodegen で生成したドキュメントとコードを Unity で利用するようになったことについて執筆いたします。
Unity への導入時につまづきをいくつか感じたため、この記事では主に導入方法について書いています。
  • Open API仕様と Swagger とは
  • 環境
  • API仕様(参考コード)
  • 導入方法
    • ビルドを通すまで
      • ドキュメント・コード生成実行する
      • Unity へのソースコードとdllの配置をする
      • 生成コードの設定をする
    • 工夫を加えた部分
      • dll を使う部分をマクロで区切りたい
      • デフォルトだと型が nullable なのを not nullable にしたい
  • 利用方法
  • まとめ

Open API仕様とSwaggerとは

Open API仕様(OAS)とは、RESTful API のインタフェースを定義するための仕様です。Swagger をベースとしています。
この仕様でインタフェースを定義することで、ドキュメント生成や各言語のコード生成をする各種ツールを利用することができます。これにより、APIの理解や利用をすばやく行うことができます。 上記の通り Open API は Swagger をベースとしているため、API仕様からソースコードを生成するツールも OpenAPI Generator というものがあるのですが、記事中では SwaggerCodegen を利用しています。どちらもメンテナンスされています。

導入モチベーションについて

Swagger を導入したいモチベーションとなったのは、各種ツールの利用による開発効率の向上の期待です。
たとえば、ツールから生成されたコードがあればサーバとクライアントのAPIの実装方法すり合わせの手間が減り、変更にも強くなります。また、ドキュメントがあれば新規開発者が戸惑わずに利用できることができます。
このような効果を期待して Swagger を導入することにしました。

環境

  • SwaggerCodegen コマンド
    • 3.0.20
    • macOS であれば brew を利用してインストールできます。
  • Unity
    • 2018.4.23f1
    • ビルド設定で Api Compatibility Level を .NET 4.x にしています。

API仕様(参考コード)

今回記事中で参考とする API仕様は以下です。Swagger サンプルのペットストアのAPI定義です。これを petstore.yml という名前で保存して使っていきます。

導入方法

ビルドを通すまで

ドキュメント・コード生成実行

SwaggerCodegen のコマンドは以下のように使っていきます。

# ドキュメント・コード生成実行
# swagger-codegen generate -i `API定義ファイルへのパス` --lang csharp -o `出力先のパス`
$ swagger-codegen generate -i petstore.yml --lang csharp -o output_dirctory

これで出力先のパス(上記だと output_dirctory)以下にドキュメントとソースコードが生成されます。

Unity へのソースコードとdllの配置をする

出力先のパス以下の src/IO.Swagger には生成されたソースコードとC#のプロジェクトファイルがあります。 Unity にはソースコードだけ移動すればいいため、以下のようにコピーします。

$ mkdir -p `Unityプロジェクトパス`/Assets/ApiDefine
$ cp -R output_dirctory/src/IO.Swagger/Api `Unityプロジェクトパス`/Assets/ApiDefine
$ cp -R output_dirctory/src/IO.Swagger/Model `Unityプロジェクトパス`/Assets/ApiDefine
$ cp -R output_dirctory/src/IO.Swagger/Client `Unityプロジェクトパス`/Assets/ApiDefine

プロジェクトファイルには依存しているライブラリの情報が書かれています。
それぞれの nupkg をダウンロード・展開して dll を用意し、Unityプロジェクトの Assets/Plugins 以下に配置します。

生成コードの設定をする

swagger-codegen は自動生成するコードに対していくつか言語特有の設定ができます。その項目は swagger-codegen config-help -l csharp で確かめることができ、設定ファイルに記述することで設定できます。 今回のAPI定義から自動生成したものはそのままだと中身が空のバリデーションコードが含まれており、IValidatableObject などを利用しています。これは Unity 2018 では参照エラーとなります。そのため validatable を false に設定することでバリデーション機能をオフにしました。
以下がバリデーション機能をオフにしたときの差分です。IValidatableObject の継承がなくなったこと、IValidatableObject.Validate が空で実装されていたことが確認できます。

src/IO.Swagger/Model/Pet.cs の diff

@@ -27,7 +27,7 @@ namespace IO.Swagger.Model
     /// Pet
     /// </summary>
     [DataContract]
+        public partial class Pet :  IEquatable<Pet>
-        public partial class Pet :  IEquatable<Pet>, IValidatableObject
     {
         /// <summary>
         /// pet status in the store
@@ -230,5 +230,14 @@ namespace IO.Swagger.Model
             }
         }
-        /// <summary>
-        /// To validate all properties of the instance
-        /// </summary>
-        /// <param name="validationContext">Validation context</param>
-        /// <returns>Validation Result</returns>
-        IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> IValidatableObject.Validate(ValidationContext validationContext)
-        {
-            yield break;
-        }
     }
 }

また、自動生成したものはそのままだと packageGuid が毎回自動生成されてしまい差分が発生するためバージョン管理に不向きです。packageGuid を設定することで固定にできます。 「バリデーション機能のオフ」、「packageGuid の設定」を加えた設定ファイル config.json は以下です。swagger-codegen で利用するようにします。

{
  "validatable": false,
  "targetFramework": "v4.5",
  "packageGuid": "..."
}


# 設定ファイルを利用したドキュメント・コード生成実行
$ swagger-codegen generate -i petstore.yml --lang csharp -o output_dirctory -c config.json

工夫を加えた部分

ここまでを行うことで Unity 上でエラーなくビルドに成功します。
ここからは自分たちの用途に合わせてカスタマイズしたことを含みます。

dll を使う部分をマクロで区切りたい

生成されたコードはAPI通信部分に RestSharp、Json 部分に NewtonSoft.JsonJsonSubTypes をそれぞれ利用しています。 Json 部分は既存のプロジェクトで他の Json ライブラリを使っていたので統一したいです。また、API通信部分についても独自の実装、または、Unityのネットワーク系メソッドを使えるようにしたいという考えがあります。 カスタマイズ用のテンプレートが公式リポジトリに用意されているため、生成されるコードにマクロを含めるようカスタマイズします。
以下のリポジトリからダウンロード・編集を行い、swagger-codegen で利用するようにします。
テンプレートは mustache ファイルです。初めて触るテンプレートファイルですが、地道に #ifdef で dll を使う部分を囲むことができました。

// ApiClient.mustache の変更の一部
// dll の using 部分
+#if SWAGGER_USE_NEWTONSOFT_JSON_DLL
using Newtonsoft.Json;
+#else
+// 他ライブラリの using の追加
+#endif // SWAGGER_USE_NEWTONSOFT_JSON_DLL

...
// Jsonパース部分
+#if SWAGGER_USE_NEWTONSOFT_JSON_DLL
                return JsonConvert.DeserializeObject(response.Content, type, serializerSettings);
+#else
+                // 他ライブラリでのJsonパース機能を実装
+#endif // SWAGGER_USE_NEWTONSOFT_JSON_DLL


# テンプレート・設定ファイルを利用したドキュメント・コード生成実行
$ swagger-codegen generate -i petstore.yml --lang csharp -o output_dirctory -c config.json -t customTemplates/csharp

デフォルトだと基本型が nullable なのを not nullable にしたい

モデル部分のコードはAPI通信だけでなく、ゲーム内のデータ定義コードとしても扱えるようにしたいです。
自動生成されるデータ定義を増やすことで、独自のデータ定義用のコードが減り、メンテナンスコストを減らしたいと考えたためです。 ゲーム中のデータでとくに数値型などは null を期待しない項目が多かったのですが、自動生成されるコードだと型が nullable でした。(例: 数値型 int でいいところが int? だった)
nullable だと実装時に考慮することが増えてしまうため not nullable にしたいです。
以下のように swagger-codegen 実行時に type-mappings オプションを指定することで一律に変更できました。

# テンプレート・設定ファイルを利用したドキュメント・コード生成実行
$ swagger-codegen generate -i petstore.yml --lang csharp -o output_dirctory -c config.json -t customTemplates/csharp --type-mappings boolean=Boolean, integer=Int32, float=Single

type-mappings での型名などは以下を参照できます。

利用方法

localhost にサーバが立っているなら、たとえば GET /pet/{petId} は以下のように利用できます。

var petApi = new IO.Swagger.Api.PetApi("http://localhost/");
var pet = petApi.GetPetById(1); // GET /pet/{petId} に相当
Debug.Log(pet);

これで利用ができました。導入完了です。

まとめ

ツールだけではないですが新しいものを扱うとき、いろいろとつまづきながらもググったり、ドキュメントを見たり、issueを見たりとしながら、使えるようになるのはとても楽しいです。 今回記事にしたのは SwaggerCodegen ですが、実際に今開発で利用しているのは OpenAPI Generator に移行しています。こちらについてもまた記事にできればと考えています。 本記事がどなたかのお役に立てればうれしいです。 3日目は Smith さんによる「golang がミジンコレベルの中年会社員が NestedText のパーサーを書いたら、そういえばまともに構文解析もやったことがないということに後から気づいたけど encode/json みたいなマーシャル処理も実装できてもう年も暮れるというのに大きな学びを得たんだが」です。異世界に飛べそうです。 ドリコムでは一緒に働くメンバーを募集しています!
募集一覧はコチラを御覧ください!