ASP.NET Core で作成した Web API のドキュメントを Swagger を使って生成する

ASP.NET Core プロジェクトで作成した Web API のドキュメントを [Swagger](http://swagger.io) を使って生成したいと思います。

# 開発環境
Mac OS X El Capitan
Visual Studio Code

# Web API アプリケーションを準備する
ASP.NET Core の Web API アプリケーションを作成済みの方はそのまま進んでください。もし作成していない場合は

* ASP.NET Core で Riot.js その１ - [プロジェクトの作成](http://qiita.com/t-koyama/items/a2b1b6bfbf401a8dd868#プロジェクトの作成)
* ASP.NET Core で Riot.js その２ - [Server-side](http://qiita.com/t-koyama/items/727d06107a1e9e00f5d2#server-side)

の部分を参考に実装して頂ければ幸いです。


# パッケージの入手
今回は .NET で Swagger を利用するためのライブラリとして Swashbuckle を使います。

*NuGet Gallery | Swashbuckle - Swagger for WebApi 5.3.2*
[https://www.nuget.org/packages/Swashbuckle/](https://www.nuget.org/packages/Swashbuckle/)

project.json を開いて `dependencies` に `"Swashbuckle"` を追加します。

```json:project.jsonの一部
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.CommandLine": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
    "Swashbuckle": "6.0.0-beta901"
  },
```

project.json を保存したら Visual Studio Code のターミナルから `dotnet restore` してパッケージを取得します。

# Startup.cs の変更
Startup.cs に Swagger を使うように処理を追加します。

```csharp:Statup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using AspRiotApp.Models;

namespace AspRiotApp
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            // リポジトリを登録
            services.AddSingleton<IPersonRepository, PersonRepository>();

            // SwaggerGen を追加
            services.AddSwaggerGen();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseMvc();

            // .tag ファイルを扱えるようにする
            var provider = new FileExtensionContentTypeProvider();
            provider.Mappings[".tag"] = "riot/tag";

            // wwwroot/index.html を起動時に表示するようにする
            app.UseDefaultFiles();

            // 静的ファイルを扱えるようにする            
            app.UseStaticFiles(new StaticFileOptions
            {
                ContentTypeProvider = provider
            });

            // UseSwagger と UseSwaggerUi を追加
            app.UseSwagger();
            app.UseSwaggerUi();
        }
    }
}
```

`ConfigureServices()` に　`services.AddSwaggerGen()` を追加して
`Configure()` に　`app.UseSwagger()` と `app.UseSwaggerUi()` を追加するだけです。



# SwaggerUI を表示する
ターミナルで `dotnet run` してブラウザーから `swagger/ui` に接続すると SwaggerUI が表示されます。

![スクリーンショット 2016-07-11 22.18.51.png](https://qiita-image-store.s3.amazonaws.com/0/128629/a396146c-96e3-ca9e-0504-6ae7cf394dc8.png "スクリーンショット 2016-07-11 22.18.51.png")

表示されている HTTP メソッドをクリックすると詳細を見ることができます。

![スクリーンショット 2016-07-11 22.21.48.png](https://qiita-image-store.s3.amazonaws.com/0/128629/c9207eaf-d202-e2ba-3bbb-b725fd33e718.png "スクリーンショット 2016-07-11 22.21.48.png")

`Try it out!` ボタンを押下することで動作の確認も可能です。

![スクリーンショット 2016-07-11 22.24.56.png](https://qiita-image-store.s3.amazonaws.com/0/128629/f2388dac-4296-1de9-f92d-3477eda6febc.png "スクリーンショット 2016-07-11 22.24.56.png")

試しに POST してみます。

![スクリーンショット 2016-07-11 22.24.12.png](https://qiita-image-store.s3.amazonaws.com/0/128629/92d8037a-7f93-41d5-0aae-8e8c6574d3d2.png "スクリーンショット 2016-07-11 22.24.12.png")

POST 後に GET してみると

![スクリーンショット 2016-07-11 22.25.48.png](https://qiita-image-store.s3.amazonaws.com/0/128629/e6d12330-e73e-5753-b335-81cab6d0b6f9.png "スクリーンショット 2016-07-11 22.25.48.png")

ちゃんと反映されています。	

# Web API の概要も表示させる (2016/07/13 追記)
Swashbuckle は Web API の概要を [XML Documentation Comments](https://msdn.microsoft.com/ja-jp/library/b2s063f7.aspx) から表示するようになっています。 概要を表示させる場合は XML Documentation Comments を Swashbuckle で利用できるように XML ファイルとして出力しておく必要があります。

## XML Documentation Comments を出力する
project.json の `buildOptions` に `"xmlDoc": true` を追加します。

```json:project.jsonの一部
"buildOptions": {
  "emitEntryPoint": true,
  "preserveCompilationContext": true,
  "xmlDoc": true
},
```

以降ビルドすると XML ファイルが出力されるようになります。デフォルトだとファイルは /bin/Debug/netcoreapp1.0/[アプリケーション名].xml として出力されます。

## XML Document Comments を読込むようにする
Startup.cs の `ConfigureServices ()` に先ほど追加した `services.AddSwaggerGen()` は引数に  `Action<SwaggerGenOptions>` を受取ってオプションを設定することができます。

概要を表示する場合はオプションとして `IncludeXmlComments()` を追加して引数に XML ファイルのパスを指定します。

```csharp:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    // リポジトリを登録
    services.AddSingleton<IPersonRepository, pository>();

    // XML Document のパスを取得する
    var location = System.Reflection.Assembly.GetEntryAssembly().Location;
    var xmlPath = location.Replace("dll", "xml");

    // SwaggerGen を追加
    services.AddSwaggerGen(options => {
    	 // XML Document Comment を読込む
        options.IncludeXmlComments(xmlPath);
    });
}
```

## コメントを付ける
概要を表示するコントローラにコメントを付けます。

```csharp:PersonController.cs
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using AspRiotApp.Models;

namespace AspRiotApp.Controllers
{
    /// <summary>
    /// PersonController
    /// </summary>
    [Route("api/v1/[controller]")]
    [Produces("application/json")]
    public class PersonController : Controller
    {
        private IPersonRepository People { get; set; }

        /// <summary>
        /// Person の一覧を取得する。
        /// </summary>
        /// <param name="people">Person リポジトリ</param>
        public PersonController(IPersonRepository people)
        {
            People = people;
        }

        /// <summary>
        /// Person の一覧を取得する。
        /// </summary>
        /// <returns>Person の一覧</returns>
        [HttpGet]
        public IEnumerable<Person> Get() => People.GetAll();

        /// <summary>
        /// ID に紐付く Person を取得する。
        /// </summary>
        /// <param name="id">取得する Person の ID</param>
        /// <returns>Personの一覧</returns>
        [HttpGet("{id}", Name="GetPerson")]
        public IActionResult Get(string id)
        {
            var person = People.Find(id);

            if(person == null)
                return NotFound();

            return new ObjectResult(person);
        }

        /// <summary>
        /// Person を作成する。
        /// </summary>
        /// <param name="person">作成する Person のパラメータ</param>
        /// <returns>IActionResult</returns>
        [HttpPost]
        public IActionResult Post([FromBody]Person person)
        {
            if (person == null)
                return BadRequest();

            People.Add(person);

            return new CreatedResult("GetPerson", person);
        }

        /// <summary>
        /// ID に紐付く Person を更新する。	
        /// </summary>
        /// <param name="id">変更する Person の ID</param>
        /// <param name="person">変更する Person のパラメータ</param>
        /// <returns>IActionResult</returns>
        [HttpPut("{id}")]
        public IActionResult Put(string id, [FromBody]Person person)
        {
            if (person == null || person.Id != id)
                return BadRequest();

            if (People.Find(id) == null)
                return NotFound();

            People.Update(person);

            return new NoContentResult();
        }

        /// <summary>
        /// ID に紐付く Person を削除する。
        /// </summary>
        /// <param name="id">削除する Person の ID</param>
        [HttpDelete("{id}")]
        public void Delete(string id) => People.Remove(id);
    }
}

```

Model クラスも Swagger 上で概要を表示できるのでコメントを付けておきます。

```csharp:Person.csd
namespace AspRiotApp.Models
{
    /// <summary>
    /// Person Model
    /// </summary>
    public class Person
    {
        /// <summary>
        /// ID
        /// </summary>
        public string Id { get; set; }

        /// <summary>
        /// 名前
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 年齢
        /// </summary>
        public int Age { get; set; }
    }
}

```

## 実行
ターミナルから `dotnet run` してブラウザから `swagger/ui` に接続すると概要が表示されるようになります。

![スクリーンショット 2016-07-13 21.48.23.png](https://qiita-image-store.s3.amazonaws.com/0/128629/e5cd0163-7af0-411c-3e78-590d1049b377.png "スクリーンショット 2016-07-13 21.48.23.png")


パラメータの内容も反映されます。

![スクリーンショット 2016-07-13 21.48.40.png](https://qiita-image-store.s3.amazonaws.com/0/128629/611f1e96-d4f2-6e34-3315-e06b6514a17c.png "スクリーンショット 2016-07-13 21.48.40.png")

上の画像の Model と Model Schema を選択するところで Model を選択すると、Model クラスに XML Document Comments を記述している場合はコメントが反映されます。

![スクリーンショット 2016-07-13 21.56.45.png](https://qiita-image-store.s3.amazonaws.com/0/128629/b348a748-a832-0848-1333-7e5352c433dd.png "スクリーンショット 2016-07-13 21.56.45.png")

# タイトルの変更と記事内容の修正および追記 (2016/07/13)
元々は『ASP.NET Core で作成した Web API のドキュメントを Swagger を使って生成する - ASP.NET Core で Riot.js その２.５』というタイトルで投稿した記事ですが、 内容が Riot.js に関係ない部分となっていますので Swagger についての独立した記事としてタイトルの変更と記事内容の修正および追記をおこないました。

# 参考
*GitHub - domaindrivendev/Swashbuckle: Seamlessly adds a swagger to WebApi projects!*
[https://github.com/domaindrivendev/Swashbuckle](https://github.com/domaindrivendev/Swashbuckle)

*ASP.NET Core RC2 WebAPIでSwaggerを利用する - とある技術の開発日記*
[http://blog.hamamotsu.jp/entry/aspdotnet-core-rc2-swagger](http://blog.hamamotsu.jp/entry/aspdotnet-core-rc2-swagger)

*ASP.NET Core 1.0 MVC API documentation using Swashbuckle Swagger | Software Engineering*
[https://damienbod.com/2015/12/13/asp-net-5-mvc-6-api-documentation-using-swagger/](https://damienbod.com/2015/12/13/asp-net-5-mvc-6-api-documentation-using-swagger/)