Extend Codegen CLI - テンプレートとデバッグ
注釈:本資料はAI技術を用いて翻訳されています。
概要
このガイドでは、Extend Codegen CLI が OpenAPI 2.0 仕様から SDK コードを生成する方法について詳しく説明します。テンプレートエンジン、カスタムフィルター、デバッグツールを理解することで、問題のトラブルシューティングやコード生成プロセスのカスタマイズに役立てることができます。
この情報は、すべての SDK テンプレートパック(Unreal、Unity、Go など)に適用されます。これらはすべて AccelByte 固有の拡張を持つ同じ Jinja2 テンプレートエンジンを使用しています。
コード生成のワークフロー
Extend Codegen CLI の核心は、シンプルなテンプレートベースのコードジェネレーターです。2 つの入力を受け取り、1 つの出力を生成します。
Makefile が複数の生成を調整する方法
テンプレートパックで make all を実行すると、実際には異なるテンプレートと出力の組み合わせで Extend Codegen CLI を複数回呼び出しています。
- Unreal
- Unity
- Go
# Unreal Makefile が行う処理の簡略例:
# 生成 1: モデルクラス
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/operations-models.j2 \
--output Models/GuildModels.h
# 生成 2: クライアント API 宣言
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-operations-decl.j2 \
--output Api/GuildApi.h
# 生成 3: クライアント API 実装
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-operations-def.j2 \
--output Api/GuildApi.cpp
# ... ファイルタイプごとに続く
# Unity Makefile が行う処理の簡略例:
# 生成 1: モデルクラス
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/operations-models.j2 \
--output Models/GuildModels.cs
# 生成 2: クライアント API クラス
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-operations.j2 \
--output Api/Guild.cs
# 生成 3: クライアント API ラッパー
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-wrapper.j2 \
--output Wrapper/GuildWrapper.cs
# ... ファイルタイプごとに続く
# Go Makefile が行う処理の簡略例:
# 生成 1: モデル構造体
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/operations-models.j2 \
--output guildService-sdk/pkg/guildserviceclientmodels/guild_models.go
# 生成 2: クライアント API 操作
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-operations.j2 \
--output guildService-sdk/pkg/guildserviceclient/guild_operations.go
# 生成 3: ショート操作ラッパー
docker run ... renderc config.yaml \
--input spec/guild.json \
--template templates/Client-short-operations.j2 \
--output guildService-sdk/pkg/guildserviceclient/guild_short.go
# ... ファイルタイプごとに続く
各 make ターゲットの基本:
- 同じ入力 1: OpenAPI 仕様ファイル(例:
guild.json) - 異なる入力 2: 特定のテンプレートファイル(例: モデル用の
operations-models.j2、ヘッダー用のClient-operations-decl.j2) - 異なる出力: 適切なディレクトリの適切な名前のターゲットファイル
SDK のコード生成がどのように機能するかを理解するには:
- Unreal
- Unity
- Go
accelbyte-unreal-sdk-template-pack.zipをダウンロードして展開するMakefileを開く — 各ターゲットがどのテンプレート、入力、出力ファイルを使用するかを示すtemplates/sdk_customization/のテンプレートファイルを調べて Jinja2 構文を確認する- テンプレートと生成された
.hおよび.cppファイルを比較して変換を確認する
accelbyte-unity-sdk-template-pack.zipをダウンロードして展開するMakefileを開く — 各ターゲットがどのテンプレート、入力、出力ファイルを使用するかを示すtemplates/sdk_customization/のテンプレートファイルを調べて Jinja2 構文を確認する- テンプレートと生成された
.csファイルを比較して変換を確認する
accelbyte-go-sdk-template-pack.zipをダウンロードして展開するMakefileを開く — 各ターゲットがどのテンプレート、入力、出力ファイルを使用するかを示すtemplates/sdk_customization/のテンプレートファイルを調べて Jinja2 構文を確認する- テンプレートと生成された
.goファイルを比較して変換を確認する
この実践的な探索が生成プロセスを理解する最良の方法です。
Jinja2 テンプレートエンジン
コード生成には、強力な Python テンプレート言語である Jinja2 を使用しています。
基本的なテンプレート構文
{# コメント - 出力には含まれない #}
{{ variable }} {# 変数の値を出力 #}
{% for item in items %} {# リストをループ #}
Process {{ item }}
{% endfor %}
{% if condition %} {# 条件ロジック #}
Do something
{% elif other_condition %}
Do something else
{% else %}
Default action
{% endif %}
{% set my_var = "value" %} {# 変数を設定 #}
{% import 'module.j2' as module %} {# 別テンプレートからマクロをインポート #}
{% macro func_name(params) %} {# 再利用可能なテンプレート関数を定義 #}
Macro content
{% endmacro %}
SDK テンプレートの例
- Unreal
- Unity
- Go
Unreal SDK テンプレート(Client-operations-decl.j2)の実際の例:
{% import 'common/services.j2' as services -%}
{% set w_class_name = service.file_stem | to_pascal %}
{% set model_prefix = "FAccelByte" + service.file_stem | to_pascal %}
class ACCELBYTEUE4SDKCUSTOMIZATION_API {{ w_class_name }} : public Core::FApiBase
{
public:
{% for operation in operations %}
/**
* @brief {{ operation.summary }}.
*/
{% if operation.responses[0].field %}
{% set response_type = operation.responses[0].field | field_unreal_type(model_prefix) %}
THandler<{{ response_type }}> const& OnSuccess,
{% endif %}
{% endfor %}
};
これにより次のような C++ コードが生成されます:
class ACCELBYTEUE4SDKCUSTOMIZATION_API Guild : public Core::FApiBase
{
public:
/**
* @brief Create a new guild.
*/
THandler<FAccelByteGuildModelsCreateGuildResponse> const& OnSuccess,
};
Unity SDK テンプレート(Client-operations.j2)の実際の例:
{% set class_name = service.file_stem | to_pascal %}
{% set namespace = "AccelByte.Api" %}
namespace {{ namespace }}
{
public class {{ class_name }}
{
{% for operation in operations %}
/// <summary>
/// {{ operation.summary }}
/// </summary>
public void {{ operation.operation_id | to_pascal }}(
{% if operation.request_body %}
{{ operation.request_body.field | field_csharp_type }} body,
{% endif %}
{% if operation.responses[0].field %}
ResultCallback<{{ operation.responses[0].field | field_csharp_type }}> callback
{% endif %}
)
{
// Implementation...
}
{% endfor %}
}
}
これにより次のような C# コードが生成されます:
namespace AccelByte.Api
{
public class Guild
{
/// <summary>
/// Create a new guild
/// </summary>
public void CreateGuild(
CreateGuildRequest body,
ResultCallback<GuildResponse> callback
)
{
// Implementation...
}
}
}
Go SDK テンプレート(Client-operations.j2)の実際の例:
{% set package_name = "guildserviceclient" %}
package {{ package_name }}
import (
"github.com/AccelByte/accelbyte-go-modular-sdk/services-api/pkg/repository"
)
{% for operation in operations %}
// {{ operation.operation_id | to_pascal }} {{ operation.summary }}
func (a *{{ service.file_stem | to_pascal }}Service) {{ operation.operation_id | to_pascal }}(
{% if operation.request_body %}
body *{{ operation.request_body.field | field_go_type }},
{% endif %}
) (*{{ operation.responses[0].field | field_go_type }}, error) {
// Implementation...
}
{% endfor %}
これにより次のような Go コードが生成されます:
package guildserviceclient
import (
"github.com/AccelByte/accelbyte-go-modular-sdk/services-api/pkg/repository"
)
// CreateGuild Create a new guild
func (a *GuildService) CreateGuild(
body *CreateGuildRequest,
) (*GuildResponse, error) {
// Implementation...
}
カスタム Jinja2 フィルター
Extend Codegen CLI はコード生成のための豊富なカスタムフィルターを提供しています。これらのフィルターは OpenAPI 仕様のデータを言語固有のコードに変換します。
フィルターはいくつかのカテゴリに分類されます。
ケース変換フィルター
異なる命名規則(PascalCase、camelCase、snake_case、kebab-case など)の間で変換します。言語固有の命名規則に従ったコードを生成するために不可欠です。
使用例:
{% set class_name = service.file_stem | to_pascal %}
class {{ class_name }} {
// "guild_service" を "GuildService" に変換
}
一般的なフィルター: to_pascal、to_camel、to_snake、to_kebab、to_sentence、to_title
言語固有の型フィルター
OpenAPI の型をターゲット言語の型に変換します。各 SDK(Unreal、Unity、Go など)は独自の型変換フィルターセットを持っています。
Unreal C++ フィルター:
- 型変換:
field_unreal_type、unreal_class、unreal_enum_value - フォーマット:
unreal_var、unreal_enum_name、field_unreal_param - 検証:
field_unreal_is_list_type
C#(Unity)フィルター:
- 型変換:
field_csharp_type、csharp_class、csharp_enum_value - フォーマット:
csharp_prop、csharp_var、csharp_enum_name - ジェネリック処理:
csharp_generic_names
Go フィルター:
- 型変換:
field_go_type、go_struct、go_var
例:
{% for field in model.properties %}
{{ field | field_unreal_type("FAccelByte") }} {{ field.name | to_pascal }};
// 生成: FString GuildName;
{% endfor %}
文字列操作フィルター
コード生成のための文字列変換と操作:
- 追加/削除:
prefix、suffix、affix、removeprefix、removesuffix - 解析:
split、strip、substr - フォーマット:
inquotes
正規表現フィルター
パターンマッチングとテキスト抽出:
- 検索:
regex_search、regex_findall - フィルター:
alnumonly、alphaonly、digitonly、numericonly
ファイルとコンテンツのフィルター
テンプレートに外部コンテンツを含める:
filecontents- ファイルの内容全体を読み込むfilesnippet- ファイルから特定の行を抽出する
ユーティリティフィルター
汎用の変換フィルター:
- コレクション:
flatten、merge - 条件分岐:
onlyif、ternary、boolean - 型処理:
typename、to_csv
例生成フィルター
ドキュメントとテスト用のサンプルデータを作成:
create_example- OpenAPI スキーマに基づいてサンプル値を生成create_example_json- JSON の例を生成create_example_wsm- WebSocket メッセージの例を生成
テンプレートパックのバージョンで利用可能なフィルターの完全なリストを確認するには、次のセクションで説明する --inspect verbose フラグを使用してください。
カスタムテンプレートを使ったデバッグと探索
コード生成を理解する最も強力な方法の一つは、独自のシンプルなテンプレートを作成し、利用可能なデータとフィルターを試してみることです。
テスト用の前提条件
テンプレートのレンダリングをテストしてデバッグするには、テンプレートパックから 3 つのものが必要です。
config.yaml- テンプレートパックの設定(すべてのテンプレートパックに含まれています)- OpenAPI 仕様 - API を記述する
guild.json(または類似の)ファイル - テンプレートファイル - 既存の
.j2ファイルまたは独自のカスタムテストテンプレート
テストテンプレートの作成
利用可能なデータを探索するための最小限のテンプレートを作成できます。test-template.j2 というファイルを作成します。
{# 利用可能なデータを探索するシンプルなテンプレート #}
サービス情報:
File Stem: {{ service.file_stem }}
Base Path: {{ service.base_path }}
操作数: {{ operations | length }}
最初の操作(存在する場合):
{% if operations %}
{% set op = operations[0] %}
Summary: {{ op.summary }}
Method: {{ op.method }}
Path: {{ op.path }}
{% endif %}
{# フィルターのテスト #}
フィルターのテスト:
to_pascal: {{ "hello_world" | to_pascal }}
to_camel: {{ "HelloWorld" | to_camel }}
to_snake: {{ "HelloWorld" | to_snake }}
テストテンプレートの実行
- Unreal
- Unity
- Go
# 展開した accelbyte-unreal-sdk-template-pack/ ディレクトリ内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my-unreal-project/spec/guild.json \
--template test-template.j2
# 展開した accelbyte-unity-sdk-template-pack/ ディレクトリ内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my-unity-project/spec/guild.json \
--template test-template.j2
# 展開した accelbyte-go-sdk-template-pack/ ディレクトリ内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my/extend-service-extension-module-sdk/spec/guild.json \
--template test-template.j2
これにより、レンダリングされたテンプレートが標準出力に出力され、以下を確認できます。
- 利用可能なデータ構造
- 各オブジェクトが持つプロパティ
- フィルターが値をどのように変換するか
詳細探索のための --inspect verbose
--inspect verbose フラグにより、完全なテンプレート環境が明らかになります。
- Unreal
- Unity
- Go
# accelbyte-unreal-sdk-template-pack/ 内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my-unreal-project/spec/guild.json \
--template test-template.j2 \
--inspect verbose
# accelbyte-unity-sdk-template-pack/ 内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my-unity-project/spec/guild.json \
--template test-template.j2 \
--inspect verbose
# accelbyte-go-sdk-template-pack/ 内から
docker run --rm \
-v "$(pwd)":"$(pwd)" \
-w "$(pwd)" \
accelbyte/extend-codegen-cli:0.0.28 renderc \
config.yaml \
--input /path/to/my/extend-service-extension-module-sdk/spec/guild.json \
--template test-template.j2 \
--inspect verbose
--inspect verbose が表示する内容:
- 入力プロセッサー情報 - OpenAPI 仕様がどのように解析されるか
- 利用可能なフィルター - すべての Jinja2 フィルター(200 以上)と関数シグネチャの完全なリスト
- グローバル関数 -
range、dict、lipsumなどの組み込み関数 - テスト関数 -
is odd、is defined、is divisiblebyなどの条件 - テンプレートローダーパス - テンプレートが検索される場所
- シンプルに始める: 変数名を出力するだけの最小限のテンプレートを作成する
- データ構造を検査する:
{{ variable }}を使用して各オブジェクトの内容を確認する - フィルターをテストする: サンプルデータでさまざまなフィルターを試して出力を確認する
- 既存のテンプレートと比較する: テンプレートパックのテンプレートを参照して実際の使用例を確認する
- 検査出力を保存する:
--inspect verbose > filters.txtを実行して後で参照できるようにする
探索用テンプレートの例:
{# デバッグテンプレート - 利用可能なすべてのデータを確認 #}
Service: {{ service }}
Operations: {{ operations }}
Models: {{ models }}
反復的なテンプレート開発
推奨アプローチ:
- テンプレートパックを展開してそのディレクトリに移動する
- 既存のテンプレートをコピーして出発点にする(例:
operations-models.j2) - シンプルなテストケースを作成する - 1 つまたは 2 つのエンドポイントを持つ最小限の OpenAPI 仕様
- 変更してテストする - 小さな変更を加えてすぐに再実行する
--inspect verboseを使用する - 特定のフィルターを見つけたり利用可能性を確認したりする必要があるとき
一般的なデバッグシナリオ
適切なフィルターを見つける:
# 検査出力を保存して検索する
docker run ... --inspect verbose > inspect.txt
grep "unreal" inspect.txt # Unreal 固有のフィルターを見つける
grep "to_" inspect.txt # ケース変換フィルターを見つける
フィルターの動作をテストする:
{# テストテンプレートを作成 #}
Original: guild_service
to_pascal: {{ "guild_service" | to_pascal }}
to_camel: {{ "guild_service" | to_camel }}
to_snake: {{ "GuildService" | to_snake }}
データ構造を理解する:
{# どのプロパティが存在するかを探索 #}
{% for operation in operations %}
Operation {{ loop.index }}:
Path: {{ operation.path }}
Method: {{ operation.method }}
Summary: {{ operation.summary }}
Parameters: {{ operation.parameters | length }}
{% endfor %}
設定ファイル(config.yaml)
各テンプレートパックの config.yaml ファイルはレンダリングプロセスを設定します。
input_processor: 'accelbyte_codegen.ext.openapi2.legacy.OA2LegacyProcessor'
template_processor: 'textf'
renderer: 'accelbyte_codegen.ext.openapi2.legacy.OA2LegacyRenderer'
extension:
- '*jinja' # 標準 Jinja2 拡張機能
- 'accelbyte_codegen.ext.openapi2.legacy.OA2LegacyExtension' # カスタムフィルター
loader:
- './templates' # テンプレート検索パス
output: 'stdout'
主要なフィールド:
input_processor: OpenAPI 2.0 の解析を処理renderer: 解析されたデータにテンプレートを適用extension: カスタムフィルターと関数をロードloader: テンプレートを検索するディレクトリ
一般的なデバッグシナリオ
生成されたコードの型が間違っている
問題: OpenAPI の integer が int ではなく string を生成する。
デバッグ手順:
- OpenAPI 仕様を確認: フィールドが
"type": "integer"として正しく定義されているか確認する --inspect verboseを使用して、ターゲット言語の正しい型変換フィルターを見つける- テンプレートファイルを調べて、どのフィルターが適用されているかを確認する
- フィルターが正しいパラメーターで呼ばれているか確認する
名前空間が欠けているか間違っている
問題: 生成されたコードの名前空間またはパッケージ名が間違っている。
デバッグ手順:
- OpenAPI 仕様の
basePathが正しいか確認する - OpenAPI の
info.titleフィールドを確認する --inspect verboseを使用して名前空間関連のフィルターを検索する- テンプレートが名前空間/パッケージ名をどのように構築するかを調べる
カスタムフィルターが機能しない
問題: テンプレートがフィルターを使用しているが、出力が間違っているか欠けている。
デバッグ手順:
--inspect verboseを実行して、フィルターがテンプレートパックのバージョンに存在するか確認する- テンプレートのフィルター名のスペルを確認する
- 入力データの型がフィルターが期待するものと一致しているか確認する(フィルターは文字列とオブジェクトで異なる動作をする場合がある)
- 最小限のテンプレートでテストして問題を切り分ける
テンプレートが見つからないエラー
問題: コード生成が "template not found" エラーで失敗する。
デバッグ手順:
--inspect verboseを実行してテンプレートローダーパスを確認する- テンプレートファイルが期待される場所に存在するか確認する
- テンプレートのファイル名またはパスのタイプミスを確認する
- Docker ボリュームマウントにテンプレートディレクトリが含まれているか確認する
テンプレートのカスタマイズ(上級)
テンプレートパックはそのまま使用できるように設計されていますが、特定のニーズに合わせてカスタマイズできます。
テンプレートのカスタマイズにより、新しいテンプレートパックのバージョンへのアップグレードが困難になる場合があります。変更内容を丁寧にドキュメント化してください。
カスタマイズの手順
-
テンプレートパックを展開する:
unzip accelbyte-unreal-sdk-template-pack.zip
cd accelbyte-unreal-sdk-template-pack/ -
変更するテンプレートを見つける:
テンプレートは
templates/sdk_customization/にあります。operations-decl.j2- API クラスの宣言operations-def.j2- API クラスの実装operations-models.j2- モデル定義
-
変更を加える:
上記のフィルターを使用して Jinja2 テンプレートファイルを編集します。
-
変更をテストする:
makeコマンドを実行して生成された出力を確認します。 -
カスタマイズをドキュメント化する:
将来の参照のために変更内容と理由を記録しておきます。
カスタマイズの例
すべての生成された API クラスにカスタムコメントを追加する:
{# operations-decl.j2 内 #}
class {{ w_class_name }} : public Core::FApiBase
{
// カスタムコメント: AccelByte Extend Codegen CLI によって生成
// OpenAPI ファイル: {{ service.file_stem }}.json
// 生成日時: {{ "now" | strftime("%Y-%m-%d") }}
public:
{% for operation in operations %}
...
{% endfor %}
};
追加リソース
- Extend Codegen CLI GitHub リポジトリ - ソースコードとイシュートラッカー
- Extend Codegen CLI Docker Hub - 利用可能な Docker イメージのバージョン
- Jinja2 ドキュメント - 公式 Jinja2 テンプレートエンジンドキュメント
- Jinja2 テンプレートデザイナードキュメント - 包括的なテンプレート構文ガイド
- OpenAPI 2.0 仕様 - OpenAPI 2.0(Swagger)仕様リファレンス
まとめ
Extend Codegen CLI のテンプレートシステムを理解することで、以下が可能になります。
--inspect verboseを使用してコード生成の問題を効果的にデバッグする- Jinja2 テンプレートを通じて OpenAPI 仕様が生成されたコードにどのようにマッピングされるかを理解する
- ターゲット言語とユースケースに適切なフィルターを使用する
- 特定の要件に応じてテンプレートをカスタマイズする
Jinja2 の柔軟性と AccelByte の豊富なカスタムフィルターの組み合わせにより、単一の OpenAPI 仕様から複数のプログラミング言語と SDK をターゲットにできる強力なコード生成システムが実現します。