.NETを使ったAPIのopenAPI定義を自動生成する

今回は、.NETを使ったAPIのopenAPI定義を自動生成する方法について書いていきたいと思います。ここでは、NSwagというパッケージを利用してopenAPI定義のjsonを自動生成します。

動機

先日、owasp zapのapi scanを使用しようとしたのですが、このスキャンでは、APIの定義ファイルが必要になります。しかし、APIの定義ファイルを一から手動で書くのは大変なので自動で作成する方法について調査しました。
このスキャンではAPIの定義をURLで指定できるので、そのAPIサーバーの中でAPI定義を取得できるAPIが自動で出来るようにしていきます。

前提

API定義を自動生成する題材としては基本的に以下の公式チュートリアルのTODOアプリ用APIを利用します。
MSLearn – チュートリアル: ASP.NET Core を使って最小 API を作成する
公式チュートリアルで作成するコード
.netのバージョンについては8.0.101を使用しました。上のリンクのgithubのコードとバージョンが異なるので、ここだけ適宜読み替えてください。

公式チュートリアルで作成するTODOアプリ用APIのコードに追記していくので、ここでは説明しませんが、まずは公式チュートリアルの手順に従って作成するか、githubから公式チュートリアルで作成するコードをダウンロードしてください。

実装

基本的な情報のみで生成

NSwagのパッケージを追加
TodoApi.csprojのItemGroupにNSwag.AspNetCoreを追加します。

<ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.1" />
    <PackageReference Include="NSwag.AspNetCore" Version="14.0.2" />
</ItemGroup>

Program.cs に以下のように追記します。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument();

・・・

var app = builder.Build();
app.UseOpenApi();
app.UseSwaggerUi();

サーバーを起動し、http://localhost:5273/swagger/v1/swagger.jsonにアクセスします。(port番号の部分は、各自の設定に合わせて下さい。サーバー起動時のログに表示されているはずです。)
以下のようなopenAPI定義のjsonが取得できます。(長いので途中一部省略しています。)

{
  "x-generator": "NSwag v14.0.2.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))",
  "openapi": "3.0.0",
  "info": {
    "title": "My Title",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "http://localhost:5273"
    }
  ],
  "paths": {
    "/todoitems": {
      "get": {
        "operationId": "GetTodoitemsAll",
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Todo"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "PostTodoitems",
        "requestBody": {
          "x-name": "todo",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Todo"
              }
            }
          },
          "required": true,
          "x-position": 1
        },
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    },

・・・

  },
  "components": {
    "schemas": {
      "Todo": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "integer",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "isComplete": {
            "type": "boolean"
          }
        }
      }
    }
  }
}

また、http://localhost:5273/swaggerにアクセスするとSwagger UIの画面で確認することができます。

APIの情報を追加

Program.csのbuilder.Services.AddOpenApiDocumentに引数を指定することで、API情報を追加することができます。
どんな項目を追加できるかは、.netのドキュメント に記載されています。
この例では、OpenAPI ドキュメントのバージョン、アプリケーションのタイトル、アプリケーションの説明、ライセンス情報を追加しています。

using NSwag;

・・・

builder.Services.AddOpenApiDocument(options => {
    options.PostProcess = document => {
        document.Info = new OpenApiInfo{
            Version = "v1.2.3",
            Title = "TODO API",
            Description = "TODO List API",
            License = new OpenApiLicense{
                Name = "Example License",
                Url = "https://example.com/license"
            }
        };
    };
});

openAPI定義のjsonを確認すると赤枠で囲った個所が更新されています。

型の情報を追加

型を定義しているコードに追記することで、データの型に注釈をつけることができます。
この例では、Nameを必須に・IsCompleateのデフォルト値をfalseにしました。
Todo.csのTodoクラスを以下のように修正します。

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

public class Todo
{
    public int Id { get; set; }
    [Required]
    public string? Name { get; set; }
    [DefaultValue(false)]
    public bool IsComplete { get; set; }
}

openAPI定義のjsonを確認すると赤枠で囲った個所が更新されています。

エンドポイントの情報を追加する

Program.csのエンドポイントを定義している関数に.WithTags(タグ名)をつけることで、tagをつけることができます。
また、.WithName(operationId)をつけることで、エンドポイント名をつけることができます。

app.MapGet("/todoitems", async (TodoDb db) =>
    await db.Todos.ToListAsync())
    .WithName("Get-TODOs-list")
    .WithTags("category-a");

openAPI定義のjsonを確認すると赤枠で囲った個所が更新されています。

終わりに

今回は、.netのAPIサーバーでopenAPI定義のJsonを自動生成しました。
動機の項目に書いたowasp zapでのスキャンに限らず、openAPIの形式に出来れば、様々なツールが対応していると思いますので、いろいろ応用が効くと思います。

参考
MS Learn – NSwag と ASP.NET Core の概要

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です