こんにちは、サイオステクノロジーの佐藤 陽です。
今回はAzureFunctionsで実装したAPIを簡単にSwaggerドキュメントにおこせるExtensionをご紹介します。
その名もAzure Functions OpenAPI Extensionです!
便利すぎて、一度使えばやみつきになるツールなので是非活用してみてください。
ちなみにこちら、Microsoftのカンファレンスでも紹介されたMSお墨付きの便利ツールです。
興味ある方はぜひこちらもご覧ください。
はじめに
APIを開発しているエンジニアのみなさん。
APIの仕様書って作っていますか?メンテナンスしていますか?
- 実装に追われ、仕様書を作る暇がない
- 一度作ったはいいけど、APIに入った修正を仕様書に反映できてない
なんてことありませんか?
また仕様書はどうやって作成していますか?
エクセル仕様書でしょうか?バージョン管理はできているでしょうか?
そんな問題を一気に解決するのが、今回ご紹介するAzureFunctions OpenAPI Extensionsです。
実装に少し修正を加えるだけでSwagger仕様書が作成されます。
また、実装コードに合わせて仕様書部分のコードも記載するため
バージョン管理が簡単に行え、メンテナンス性にも優れます。
OpenAPI/Swaggerとは?
OpenAPI?Swagger?なにそれ?という方もいらっしゃるかと思うので簡単にご紹介します。
簡単に言ってしまうと、REST APIの仕様書を作成するための仕様およびツールです。
サンプルを見せると、このような画面のものです。
見たことある方も多いのではないでしょうか?
また、よくOpenAPIとSwaggerの違いについて言及されることがありますが
OpenAPI:仕様書を記述する仕様
Swagger:OpenAPI仕様に基づいたものを実装するツール
という定義になります。
詳細に関してはSwagger公式に記載があるので興味のある方はこちらをご覧ください。
実際に作ってみよう!
準備編
仕様書を作るためにはまずAPIが必要となってくるため、プロジェクトを用意します。
今回はVisualStudio上でAzureFunctionsのテンプレートを利用してプロジェクトを作成します。
実行環境は.NET 6で進めていきます。
プロジェクトが作成されると、サンプル関数が一つ存在しているかと思います。
今回はこれを少し修正して、以下のような関数を一つ作成しました。
public static class Function
{
[FunctionName("GetName")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "{country}/names")] HttpRequest req,
string country, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
if (string.IsNullOrEmpty(name))
{
return new BadRequestObjectResult("Name parameter not found");
}
else
{
return new OkObjectResult($"Hello, {name} from {country}. This HTTP triggered function executed successfully.");
}
}
}
早速実行してみましょう!
すると、コンソールログが表示され、API実行のためのエンドポイントが一つ表示されます。
適当にパラメータを追加して、APIをブラウザで実行すると…
localhost:7135/api/japan/names?name=sios
正しく実行できていることが確認できます。
ひとまずこれでAPIの動作自体はOKですね。
では実際にこのAPIをSwaggerドキュメントに起こしていきたいと思います。
Extensionのインストール
VisualStudioのNuGetコンソールから以下二つのExtensionをインストールします。
- Microsoft.Azure.WebJobs.Extensions.OpenApi
- Microsoft.Azure.WebJobs.Extensions.OpenApi.Core
APIの仕様を追記
では次に、作成したAPIの仕様を記載していきます。
FunctionNameのAttribute下に以下のようなAttributeを加えます。
[FunctionName("GetName")]
//以下を追加
[OpenApiOperation(operationId: "GetName", tags: new[] { "name" }, Summary = "Gets the name", Description = "This gets the name.", Visibility = OpenApiVisibilityType.Important)]
[OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = false, Type = typeof(string), Summary = "The name", Description = "Enter Your name", Visibility = OpenApiVisibilityType.Important)]
[OpenApiParameter(name: "country", In = ParameterLocation.Path, Required = true, Type = typeof(string), Summary = "The country", Description = "Enter your country", Visibility = OpenApiVisibilityType.Important)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Summary = "The response", Description = "Success")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "text/plain", bodyType: typeof(string), Summary = "The response", Description = "Fail")]
//ここまで
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "{country}")] HttpRequest req,
それぞれのAttributeを簡単に説明すると
OpenApiOperation | このAPIに対する概要情報を示しています。 どんなAPIなのかを記載したり、タグ付けしてSwagger上でグループ分けを行えたりします。 |
OpenApiParameter | リクエストパラメータです。 クエリパラメータなのか、パスパラメータなのか、どういった値なのかの記述を行う事ができます 必須パラメータなのか、任意のパラメータなのかも指定できます。 |
OpenApiResponseWithBody | レスポンスパラメータです。 このAPIがどのような値を返すのかを定義します。 複数指定することも可能で、成功した場合や失敗した場合にどのような値が返されるかの記述を行うことができます。 |
Swaggerドキュメント生成
この状態で一度アプリケーションをビルドしてみます。
すると、先ほどのGetNameの関数に加えて4つほど新規にエンドポイントが表示されていることが分かります。
http://localhost:7135/api/swagger/ui
をブラウザにて実行してみると…
実装したAPIのSwaggerドキュメントが生成されます!!
たった数行加えただけで、こんなにおしゃれな仕様書が作成されるなんて感動ですね。
またコードと隣り合ってAttributeを記載するため、
実装に変更があった際もついでに直そうかという気にもなりますし、
Git等のバージョン管理ツールで合わせて管理できるため、メンテナンスも楽ですね。
もちろんTry it outボタンを押して実際に関数を実行することができます。
公開するための仕様書としても使えますが、開発時なども便利そうですね。
デプロイ
今回、実際にデプロイまでは行いませんが
もちろんAzureFunctionsにデプロイした後も利用できます。
ここでポイントなのが、Swaggerのドキュメントは静的なサイトとしてデプロイされていないことです。
swagger.uiをcallするたびに動的に情報が取得されUIが描画され表示されます。
そのため、運用コストとしてはAzureFunctionsのAPIコール2回分です。
(1回ではなく、2回な理由は後述のおまけを参照)
おまけ
試しに
http://localhost:7135/api/swagger.json
を実行してみてください。
すると、json形式のレスポンスが得られるかと思います。
じつはこれがOpenAPIの仕様に則って書かれたコードになります。
Swaggerはこのjson形式のコードをベースにUIを作成することになります。
api/swagger/uiのエンドポイントにアクセス後、コンソールログをみるとapi/swagger.jsonも実行されていることが分かります。
これはapi/swagger/uiの処理として
- api/swagger.jsonを実行してjsonのレスポンスを取得
- レスポンスを元にUIを描画
というステップを踏んでいるためです。
まとめ
今回はSwaggerを簡単に生成できるExtensionをご紹介しました。
APIのドキュメントを作成・管理するのってなかなか大変ですよね。
このExtensionを使う事でその手間がだいぶ緩和されるのではないでしょうか。
是非使ってみてくださいね。