これはドリコム Advent Calendar 2020 の2日目です。
1日目は ogwmtnr さんによる「コロナ禍、リモートワーク、新生児との生活を振り返ってみる」です。 こんにちは。DRIP エンジニアの広井淳貴です。
DRIP は Drecom Invention Project の略称で、ドリコムが発明を産み続けるためのプロジェクトです。
その中でわたしは「AROW」というプロジェクトで活動しています。AROW では3Dリアルマップの研究開発を行っていて、没入感のある新しいゲーム体験の実現を目指すために現在開発中です。
Unity への導入時につまづきをいくつか感じたため、この記事では主に導入方法について書いています。
この仕様でインタフェースを定義することで、ドキュメント生成や各言語のコード生成をする各種ツールを利用することができます。これにより、APIの理解や利用をすばやく行うことができます。 上記の通り Open API は Swagger をベースとしているため、API仕様からソースコードを生成するツールも OpenAPI Generator というものがあるのですが、記事中では SwaggerCodegen を利用しています。どちらもメンテナンスされています。
たとえば、ツールから生成されたコードがあればサーバとクライアントのAPIの実装方法すり合わせの手間が減り、変更にも強くなります。また、ドキュメントがあれば新規開発者が戸惑わずに利用できることができます。
このような効果を期待して Swagger を導入することにしました。
それぞれの nupkg をダウンロード・展開して dll を用意し、Unityプロジェクトの
以下がバリデーション機能をオフにしたときの差分です。
ここからは自分たちの用途に合わせてカスタマイズしたことを含みます。
以下のリポジトリからダウンロード・編集を行い、
テンプレートは mustache ファイルです。初めて触るテンプレートファイルですが、地道に
自動生成されるデータ定義を増やすことで、独自のデータ定義用のコードが減り、メンテナンスコストを減らしたいと考えたためです。 ゲーム中のデータでとくに数値型などは null を期待しない項目が多かったのですが、自動生成されるコードだと型が nullable でした。(例: 数値型
nullable だと実装時に考慮することが増えてしまうため not nullable にしたいです。
以下のように
募集一覧はコチラを御覧ください!
1日目は ogwmtnr さんによる「コロナ禍、リモートワーク、新生児との生活を振り返ってみる」です。 こんにちは。DRIP エンジニアの広井淳貴です。
DRIP は Drecom Invention Project の略称で、ドリコムが発明を産み続けるためのプロジェクトです。
その中でわたしは「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.Json
、JsonSubTypes
をそれぞれ利用しています。
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=Singletype-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);
GET /pet/{petId}
の定義
まとめ
ツールだけではないですが新しいものを扱うとき、いろいろとつまづきながらもググったり、ドキュメントを見たり、issueを見たりとしながら、使えるようになるのはとても楽しいです。 今回記事にしたのは SwaggerCodegen ですが、実際に今開発で利用しているのは OpenAPI Generator に移行しています。こちらについてもまた記事にできればと考えています。 本記事がどなたかのお役に立てればうれしいです。 3日目は Smith さんによる「golang がミジンコレベルの中年会社員が NestedText のパーサーを書いたら、そういえばまともに構文解析もやったことがないということに後から気づいたけど encode/json みたいなマーシャル処理も実装できてもう年も暮れるというのに大きな学びを得たんだが」です。異世界に飛べそうです。 ドリコムでは一緒に働くメンバーを募集しています!募集一覧はコチラを御覧ください!