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

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

今回は、.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 の概要

アバター画像
About 藤井 8 Articles
2020年サイオステクノロジーに入社。入社後は主にgo言語とtypescriptを使ったAPI開発を行う。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

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

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


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる