概要
- REST APIのクライアントを作成する際、Open API GeneratorやSwagger Codegenを利用してコードを自動生成することが多いと思います。
- しかし、生成されたコードが期待していたものとちょっと異なることがあります。
- この記事では、自動生成用のテンプレートをカスタマイズして、希望通りのコードを生成する方法を紹介します。
環境
- Windows 10 Professional
- Java 1.8.0
- Visual Studio 2017
カスタマイズ内容
- 今回は、C#用のテンプレートをカスタマイズします。
- 自動生成コードのビルドが通らなかったので、ビルドを通します。
- 他の言語でもテンプレートが異なるだけで手順は同じです。
Open API Generatorのダウンロード
以下のファイルを任意のフォルダにダウンロードします。
以降、Open API Generatorを例に説明を行いますが、Swagger Codegenでもほぼ同じ手順になります。
サンプルAPI
サンプルとして、helloインターフェイスを定義します。
リクエスト
GET /hello
レスポンス
{
"message": "Hello world!"
}
YAMLファイルは以下になります。
openapi: 3.0.0
servers:
- url: 'http://localhost:8080/service/v1'
info:
version: 1.0.0
title: Service API
tags:
- name: Hello
paths:
/hello:
get:
tags:
- Hello
summary: Hello
description: hello
operationId: hello
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Message'
components:
schemas:
Message:
type: object
properties:
message:
type: string
コード生成
クライアントコードを生成します。
コード生成の前準備として、openapi-generator-cli-4.2.3.jarのあるフォルダに以下のファイルを作成します。
- openapi.yaml : API定義(前述)
- codegen_config.json : コンフィグレーションファイル
- csharp-client.bat : コード生成バッチファイル
{
"packageName": "service",
"optionalAssemblyInfo": false,
"optionalProjectFile": false
}
cd %~dp0
set executable=openapi-generator-cli-4.2.3.jar
set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M
set args=generate -i openapi.yaml -g csharp -o .gen_client -c codegen_config.json --additional-properties hideGenerationTimestamp=true
java %JAVA_OPTS% -jar %executable% %args% > log.txt
csharp-client.batを実行して、コードを生成します。
> csharp-client.bat
.gen_client以下のフォルダにコードが生成されます。
+ .gen_client
+ src
+ service
+ Api
+ HelloApi.cs
+ Client
+ ApiClient.cs
+ ApiException.cs
+ ApiResponse.cs
+ Configuration.cs
+ ExceptionFactory.cs
+ GlobalConfiguration.cs
+ IApiAccessor.cs
+ IReadableConfiguration.cs
+ OpenAPIDateConverter.cs
+ Model
+ Message.cs
ビルド
Visual Studio 2017で[ファイル]-[新規作成]-[プロジェクト]-[.NET Standard]-[クラスライブラリ (.NET Standard)]を選択して、
プロジェクトを作成します。(ここではHelloClientとします)
プロジェクトを作成したフォルダに自動生成したコードをコピーします。
フォルダ構成が以下の通りになるようにApi, Client, Modelフォルダを配置します。
+ HelloClient
+ HelloClient.csproj
+ Api
+ HelloApi.cs
+ Client
+ ApiClient.cs
+ ApiException.cs
+ ApiResponse.cs
+ Configuration.cs
+ ExceptionFactory.cs
+ GlobalConfiguration.cs
+ IApiAccessor.cs
+ IReadableConfiguration.cs
+ OpenAPIDateConverter.cs
+ Model
+ Message.cs
プロジェクトの[依存関係]<右クリック>-[Nugetパッケージの管理]から以下をインストールします。
Microsoft.CSharp v4.7.0
System.ComponentModel.Annotations v4.7.0
RestSharp v106.10.1
Newtonsoft.Json v12.0.3
ビルドすると、エラー1件とワーニング1件が発生しました。
1>Client\ApiClient.cs(137,51,137,69): error CS1503: 引数 2: は 'System.Action<System.IO.Stream>' から 'byte[]' へ変換することはできません。
1>Client\ApiClient.cs(207,34,207,70): warning CS0618: 'RestClient.ExecuteTaskAsync(IRestRequest)' は旧形式です ('Use ExecuteAsync instead')
ApiClient.csでエラーになっているので、ApiClient.csを生成するためのテンプレートに間違いがあるのかもしれません。
テンプレートのカスタマイズ
テンプレートファイルを探す
まずは、openapi-generator-cli-4.2.3.jarの中からテンプレートファイルを見つけます。
ファイルの拡張子をjarからzipに変更して展開すると、プログラミング言語毎にフォルダが分かれていることが分かります。
C#用のテンプレートはcsharpフォルダに入っており、ApiClient.mustacheがApiClient.csのテンプレートファイルだと推測がつきます。
csharp\ApiClient.mustache
テンプレートファイルの拡張子が.mustacheなので、テンプレートエンジンとしてmustacheを使用していることが分かります。
テンプレートファイルの抽出
修正したいテンプレートファイルをopenapi-generator-cli-4.2.3.jarから取り出します。
> jar -xvf openapi-generator-cli-4.2.3.jar csharp/ApiClient.mustache
csharp/ApiClient.mustacheが展開されました
csharpフォルダにApiClient.mustacheファイルが作成されます。
テンプレートファイルの編集
抽出したテンプレートファイルを編集します。
error CS1503: 引数 2: は 'System.Action' から 'byte[]' へ変換することはできません。
IRestRequest.AddFile()の呼び出しで、引数が足りない(ContentLengthの指定が抜けている)ようなので追加します。
// Creates and sets up a RestRequest prior to a call.
private RestRequest PrepareRequest(
...)
{
...
// add file parameter, if any
foreach(var param in fileParams)
{
...
// 変更前
//request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType);
// 変更後
request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentLength, param.Value.ContentType);
...
}
...
}
warning CS0618: 'RestClient.ExecuteTaskAsync(IRestRequest)' は旧形式です ('Use ExecuteAsync instead')
IRestClient.ExecuteTaskAsync()はもう古いみたいなので、ExecuteAsync()に変更します。
public async System.Threading.Tasks.Task<Object> CallApiAsync(
...)
{
...
// 変更前
//var response = await RestClient.Execute{{^netStandard}}TaskAsync{{/netStandard}}(request);
// 変更後
var response = await RestClient.Execute{{^netStandard}}Async{{/netStandard}}(request);
...
}
テンプレートファイルの更新
jarファイル内のテンプレートファイルを上書きします。
> jar -uf openapi-generator-cli-4.2.3.jar csharp/ApiClient.mustache
コード生成&ビルド
生成されたファイルをプロジェクトフォルダにコピーして、再度コードを生成します。
> csharp-client.bat
ビルドすると今度は通りました。
========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========
まとめ
- 自動生成用のテンプレートをカスタマイズして、希望通りのコードを生成しました。
- 今回はビルドを通しただけですが、エラー処理やログ出力などをカスタマイズできると便利です。
- 今回はOpen API Generatorをカスタマイズしましたが、Swagger Codegenも同様にカスタマイズ可能です。
- 今回はC#を例にカスタマイズしましたが、他の言語も同様にカスタマイズ可能です。