ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

ASP.NET Web API の Swagger ドキュメントでコメントを改行する

ASP.NET Web API では、Swashbuckle を使って Swagger ドキュメントを作成します。
具体的な手順は、過去の記事を参照してください。
gooner.hateblo.jp

例えば、GUID 型の ID を指定して取得する API を実装すると、Swagger ドキュメントでは string 型として扱われます。

[RoutePrefix("api/persons")]
public class PersonController : ApiController
{
	/// <summary>
	/// Person を取得します。
	/// </summary>
	/// <param name="id">
	/// <para>取得する Person ID。</para>
	/// <para>GUID 形式で指定します。</para>
	/// </param>
	/// <returns></returns>
	[Route]
	public Person Get(Guid id)
	{
		return new Person { Id = id, Name = "Test" };
	}
}

そのため、para タグを使ってパラメータのコメントを改行しているのですが、Swagger ドキュメントでは改行されずに読みづらくなってしまいます。

f:id:TonyTonyKun:20160809175546p:plain

改行するには、Swagger ドキュメントをカスタマイズする方法があります。
元ネタは、GitHub の Issues に挙がっている内容です。
github.com

Swagger ドキュメントをカスタマイズする

Swashbuckle の IOperationFilter インターフェイスを利用すると、Swagger メタデータ プロセスのさまざまな部分をカスタマイズできる拡張ポイントが提供されます。
IOperationFilter インターフェイスを継承した FormatXmlCommentsFilter クラスを実装しました。

public class Startup
{
	public void Configuration(IAppBuilder app)
	{
		var config = new HttpConfiguration();
		config.MapHttpAttributeRoutes();

		// Swashbuckle の構成
		config.EnableSwagger(c =>
		{
			c.SingleApiVersion("v1", "WebApplication4");
			c.IncludeXmlComments($@"{AppDomain.CurrentDomain.BaseDirectory}bin\WebApplication4.XML");
			c.OperationFilter<FormatXmlCommentsFilter>();
		})
		.EnableSwaggerUi(c =>
		{
		});

		app.UseWebApi(config);
	}
}

Apply メソッドでパラメータのコメントに対して、para タグを p タグに変換するロジックを入れています。

public class FormatXmlCommentsFilter : IOperationFilter
{
	public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
	{
		foreach (var parameter in operation.parameters)
		{
			parameter.description = Formatted(parameter.description);
		}
	}

	private string Formatted(string description)
	{
		if (description == null) return null;
		return new StringBuilder(description).Replace("<para>", "<p>").Replace("</para>", "</p>").ToString();
	}
}

Swagger ドキュメントで、パラメータのコメントが改行されるようになります。

f:id:TonyTonyKun:20160809175701p:plain

まとめ

IOperationFilter インターフェイスの Apply メソッドの引数を見ると、Swagger ドキュメントの JSON データを比較的自由にカスタマイズできることが分かります。
para タグぐらいは、Swashbuckle 側で対応してくれてもいい気もしますが、今回はカスタマイズして対応することにしました。

ASP.NET Web API の Swagger ドキュメントからパラメータのモデル名を削除する

ASP.NET Web API では、Swashbuckle を使って Swagger ドキュメントを作成します。
具体的な手順は、過去の記事を参照してください。
gooner.hateblo.jp

アクションメソッドに FromUri 属性を指定すると、URI のパラメータを自分で定義したクラスにバインドできます。開始と終了のコードを指定して検索できる API であれば、次のように実装できます。

[RoutePrefix("api/persons")]
public class PersonController : ApiController
{
	[Route]
	public IEnumerable<Person> Get([FromUri]PersonGetParameters model)
	{
	}
}

public class PersonGetParameters
{
	public string StartCode { get; set; }
	public string EndCode { get; set; }
}

Swagger UI で確認すると、以下のように表示されます。

f:id:TonyTonyKun:20160725153354p:plain
API の動作としては、以下のどちらの URL でもリクエストできるので間違いではないのですが、少し格好悪いので Swagger ドキュメントから「model.」を削除したくなります。

  • api/persons?model.startCode=001&model.endCode=002
  • api/persons?startCode=001&endCode=002

削除するには、2通りの対応があります。
元ネタは、GitHub の Issues に挙がっている内容です。
github.com

モデル名を含めたリクエストを許可しない

API の URL ルーティングとして、モデル名を含めたリクエストを許可しないことで、Swagger ドキュメントからも「model.」が削除されます。必要な実装は、FromUri 属性の Name プロパティに Empty をセットするだけです。

[Route]
public IEnumerable<Person> Get([FromUri(Name = "")]PersonGetParameters model)
{
}

f:id:TonyTonyKun:20160725153412p:plain

Swagger ドキュメントをカスタマイズする

Swashbuckle の IOperationFilter インターフェイスを利用すると、Swagger メタデータ プロセスのさまざまな部分をカスタマイズできる拡張ポイントが提供されます。
IOperationFilter インターフェイスを継承した MyOperationFilter クラスを実装しました。

public class Startup
{
	public void Configuration(IAppBuilder app)
	{
		var config = new HttpConfiguration();
		config.MapHttpAttributeRoutes();

		// Swashbuckle の構成
		config.EnableSwagger(c =>
		{
			c.SingleApiVersion("v1", "WebApplication4");
			c.IncludeXmlComments($@"{AppDomain.CurrentDomain.BaseDirectory}bin\WebApplication4.XML");
			c.OperationFilter<MyOperationFilter>();
		})
		.EnableSwaggerUi(c =>
		{
		});

		app.UseWebApi(config);
	}

}

Apply メソッドでパラメータ名を変換すると、Swagger ドキュメントからも「model.」が削除されます。

public class MyOperationFilter : IOperationFilter
{
	public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
	{
		if (operation.parameters != null)
		{
			foreach (var pram in operation.parameters)
			{
				// 例)"model.startCode" → "startCode" に変換
				var index = pram.name.IndexOf(".");
				if (index != -1)
				{
					pram.name = pram.name.Substring(index + 1);
				}
			}
		}
	}
}

まとめ

シンプルな API であれば、アクションメソッドに int や string などのプリミティブ型で十分対応できますが、指定できる検索条件が多くなると自分で定義したクラスにパラメータをバインドしたくなります。
その際に、モデル名を削除する方法を2通り紹介しました。

  • モデル名を含めたリクエストを許可しない
  • Swagger ドキュメントをカスタマイズする

Swagger ドキュメントをカスタマイズする方法では、重複したパラメータ名が出力される可能性があります。
1つの API で複数の URL ルーティングをサポートする必要性はないので、モデル名を含めたリクエストを許可しない方が良いのかなと思います。

書籍「Microservices on Azure」の感想

先月の JAZUG の勉強会で Azure Service Fabric の話を聞いて、読んでみたくなった書籍でした。既にマイクロサービスという用語がバズワードになっている感もあって、実際どうなんだろうなあと思っていましたが、de:code 2016 に参加してその重要性を肌で感じたので購入しました。

Microservices on Azure

Microservices on Azure

  • 作者: ボブ・ファミリア,株式会社クイープ
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/04/22
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

なぜ今マイクロサービスなのか

クラウドを使うことが当たり前の時代となり、顧客の要求は絶えず変化し、そのスピードも速くなっています。エンジニアは、より多くの機能を、より短い時間で、より少ないリソースで提供することが求められます。もっとクラウドのメリットを活用して効率よくアプリケーションを開発したくなるわけです。
そのためには、開発だけではなく、デプロイメントやメンテナンスも含めた全体のプロセスを変えていく必要があり、第1~3章ではモノリシックな階層型アーキテクチャと比較しながら、マイクロサービスの重要性を分かりやすく解説しています。

リファレンス実装

第4~7章では、Azure Storage、SQL Database、DocumentDB、Redis Cache、Web Appsなど基本的なサービスに加え、IoT で使うことが多い Event Hubs や Stream Analytics も含めて、概要とリファレンス実装が記載されていて、Azure 初心者にも易しいです。
Azure PowerShell を使った自動化も含まれているので、継続的インテグレーションやデプロイまで試すことができます。ちなみに、Azure API Management について書かれている本を読んだのは、初めてでした。

Azure Service Fabric

第8章では、Azure Service Fabric の概要やプログラミングモデルが分かりやすく解説されています。プレビューだった頃のバージョンですが、Service Fabric SDK をインストールして、ローカル環境で試す手順も記載されています。実際にコードが記載されていると、具体的なイメージがつかみやすくて良かったです。

まとめ

これまでのクラウドの普及と進化が、どうしてマイクロサービスにつながってくるのかを整理できた気がします。クラウドプラットフォームにどんなアーキテクチャでアプリケーションを開発していけばよいのか、いま改めて考える際のガイダンスがマイクロサービスだと思いました。

余談

デスクの横に積み上げられていく書籍の山を増やしたくなかったので、Kindle Paperwhite を購入しました。ブラックの Wi-Fi モデルに純正カバーもつけました。だいぶ割高感のあるカバーでしたが、Amazonプライム会員で 4,000円OFF だし、まあ良しとしました。

Kindle Paperwhite Wi-Fi 、ブラック、キャンペーン情報つき

Kindle Paperwhite Wi-Fi 、ブラック、キャンペーン情報つき

Amazon Kindle Paperwhite用レザーカバー、ミッドナイトブルー (Kindle Paperwhite専用)

Amazon Kindle Paperwhite用レザーカバー、ミッドナイトブルー (Kindle Paperwhite専用)

スマホやタブレットと比べて、文字が読みやすいですし、軽くて薄いので気軽に持ち運べて便利です。紙の書籍でなくても、十分ありだと思いました。ただ、「1-Clickで買う」ボタンは簡単に購入できて危険なので、調子に乗ってクリックし過ぎないように気をつけたいです。