noxi雑記

.NET、Angularまわりの小ネタブログ

ASP.NET CoreのWebAPIとAutoRestで良い感じの.NETクライアントライブラリーを生成する

AutoRest は OpenAPI( Swagger )で定義された RestAPI に接続するクライアントコードを生成するライブラリーです。 ASP.NET Core で実装した WebAPI に対して AutoRest で良い感じのクライアントライブラリーを生成する時のポイントメモです。

github.com



環境

  • .NET Core SDK 3.1.100
  • ASP.NET Core 3.1 + Swashbuckle.AspNetCore@5.0.0-rc.5
  • Node.js 12.14.1
  • npm 6.13.6
  • AutoRest 3.0.5231

AutoRestのクライアント生成

事前準備

AutoRest でクライアントライブラリーを生成するには Node.js 10.x 以上と .NET Core 2.0 SDK が必要なのでインストールしておきます。
また生成したクライアントコードは API に接続するコードのみで CS プロジェクトファイルは含まれないため、事前に .NET Standard 2.0 のライブラリープロジェクトを1つ作成しておきます。作成したプロジェクトには Microsoft.Rest.ClientRuntime を NuGet から追加することを忘れずに。

クライアントコードの生成

クライアントコードを生成するため、先に作成したライブラリープロジェクト上にコードを生成します。 OpenAPI v3 のコードを生成するには AutoRest 3.x が必要なため @beta を付与して実行します。

npx autorest@beta --csharp --namespace="ApiClient" --input-file="http://localhost:5000/swagger/v1/swagger.json" --output-folder="xxxxxxxxxx"

f:id:noxi515:20200112152338p:plain
生成されたクライアントコード

OpenAPI で設定されたタグに応じてファイルを分割してくれないため、生成された WebAPIExtensions.cs を眺めると全ての API に接続する拡張メソッドが含まれており、名前も重複して Get1Async となっていてとても残念な感じです。

f:id:noxi515:20200112153233p:plain
名前が重複している拡張メソッド群

良い感じのクライアントコード生成

AutoRest で良い感じのクライアントコードを生成するには OperationId に一工夫加える必要があります。 AutoRest では OperationId に含まれる _ 毎にクライアントコードが分割されるため、 OpenAPI 定義を生成する際に例えばコントローラー名を OperationId に含めるなどします。

SwashbuckleでOperationIdにコントローラー名をPrefixにする

Swashbuckle には OpenAPI 定義を生成するのにいくつかの設定があります。そのうち IOperationFilter を使用すると生成される OpearationId を任意にカスタマイズすることができます。例えばコントローラー名を付与するならこんな感じになります。

public class CustomOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor controller)
        {
            operation.OperationId =
                $"{controller.ControllerName}_{operation.OperationId ?? controller.ActionName}";
        }
    }
}

作成した IOperationFilterAddSwaggerGen で設定します。

/// <summary>
/// OpenAPIミドルウェアの設定を追加します。
/// </summary>
public static void AddOpenApi(this IServiceCollection services)
{
    services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "WebAPI",
            Version = "v1.0.0"
        });
        options.OperationFilter<CustomOperationFilter>();  // ココ
    });
}

クライアントコードの生成

OperationId にコントローラー名を付与したら再度 AutoRest でクライアントコードを生成してみます。今回はコントローラー毎に分かれたクライアントコードが生成されました。

f:id:noxi515:20200112154608p:plain
コントローラー毎に分割されて生成されたクライアントコード