【Unity】OpenAPIスキーマからカスタムテンプレートでレスポンスクラスを自動生成する

## 本記事について
OpenAPI Generatorを使ってUnityで使うC#のコードを自動生成する方法を紹介

## Sampleリポジトリ

以下のサンプルリポジトリに本記事の内容は全て含まれている。
Dockerさえあればすぐに試せるため、詳しくはこちらのリポジトリを直接見ていただければ！

https://github.com/teach310/unity-openapi-sample-schema

## 環境
Mac
Docker
APIのやりとりはJSON
UnityのJSONのparseにはJsonUtilityを使う想定。(他のライブラリの場合でもテンプレートを少しいじれば問題ない)
OpenAPI 3.0.3 (執筆時点でOpenAPI Generatorが3.1.0に対応していない)

## OpenAPI のスキーマから C# のコードを生成するメリット

- ミスがなくなる: スキーマに定義されてない知らないプロパティーがクライアントで使われている..!ということが起こり得ない。
- コードを書く時間の節約: 手作業より早い
- 保守性が高い: スキーマを変更時の反映が容易
- コミュニケーションコスト: サーバー、クライアント間のコミュニケーションコストを劇的に下げることができる。

API使うならクライアントのコードを自動生成する以外に選択肢ないまである。

## OpenAPI Generatorについて
https://github.com/OpenAPITools/openapi-generator

openapi.ymlからコードを生成するツール。
csharpのコード生成もできるが、Unityで使うための設定はない(2023/3時点)

そこでテンプレートをいじってUnityで扱いやすいシンプルなコードを生成するようにした。

csharpのテンプレートは以下にある。

https://github.com/OpenAPITools/openapi-generator/tree/v6.4.0/modules/openapi-generator/src/main/resources/csharp

大量にあるが、本記事で扱うのは以下のみ。
`model.mustache`, `modelGeneric.mustache`

mustacheって何？となる場合にはとりあえず以下だけ覚えておけばなんとかなる。

```
{{#hoge}}
hogeがあったらここが生成される
{{/hoge}}
```

```
// modelGeneric.mustacheを呼び出す
{{>modelGeneric}}
```

## テンプレートの修正

- 不要なusing, メソッド、属性を削除
- JsonUtilityで扱うためにSerializableを追加
- プロパティーのシリアライズは厳しいためフィールド追加
- コンストラクタを修正

等の修正を行ったのが以下。

https://github.com/teach310/unity-openapi-sample-schema/tree/main/generator/csharp/templates

これによって以下のようなコードを生成できる

```.cs
/*
 * Unity OpenAPI Sample
 *
 * Sample API
 *
 * The version of the OpenAPI document: 1.0.0
 * 
 * Generated by: https://github.com/openapitools/openapi-generator.git
 */

using UnityEngine;
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;

namespace Sample.Model
{
    /// <summary>
    /// Monster
    /// </summary>
    [Serializable]
    public partial class Monster
    {
        /// <summary>
        /// Gets or Sets Id
        /// </summary>
        [SerializeField] private long id;
        public long Id { get => id; set => id = value; }
        /// <summary>
        /// Gets or Sets Name
        /// </summary>
        [SerializeField] private string name;
        public string Name { get => name; set => name = value; }
        /// <summary>
        /// Gets or Sets Tag
        /// </summary>
        [SerializeField] private string tag;
        public string Tag { get => tag; set => tag = value; }

        public Monster()
        {
        }

        public Monster(long id, string name, string tag)
        {
            this.id = id;
            this.name = name;
            this.tag = tag;
        }

        /// <summary>
        /// Returns the string presentation of the object
        /// </summary>
        /// <returns>String presentation of the object</returns>
        public override string ToString()
        {
            var sb = new StringBuilder();
            sb.Append("class Monster {\n");
            sb.Append("  Id: ").Append(Id).Append("\n");
            sb.Append("  Name: ").Append(Name).Append("\n");
            sb.Append("  Tag: ").Append(Tag).Append("\n");
            sb.Append("}\n");
            return sb.ToString();
        }
    }
}

```

## 他のスキーマ言語比べてどうなのか

OpenAPIの場合ネットに情報が多く、周辺ツールも充実している点が優れていると考える。
ただし、そもそもコードを自動生成するためのものではないため、カスタマイズはしづらい。
シンプルなクラス生成したいだけなら十分使える。あと導入がとても楽。

## 参考

mustache記法について簡単にまとめてみた
https://qiita.com/sengok/items/1d958348215647a5eaf0

ReadableなOpenAPI定義ファイルを書く
https://blog.nnn.dev/entry/2022/04/20/110000

openapi-generator で自作テンプレートを用いて iOS API クライアントを自動生成した話
https://qiita.com/tasuwo/items/5e3aa7af8d4fee55714f

swagger-merger を用いた大規模API開発における Swagger 運用
https://techblog.finatext.com/swagger-merger-5e29bd27907