ASP.NET Web API における Swagger の設定と利用

Swagger の設定

ASP.NET Web API プロジェクトで Swagger を有効にし、API ドキュメントを自動生成するための設定方法を説明します。ここでは、Swashbuckle ライブラリを使用します。

1. 設定コード

以下は、Swagger の機能をカスタマイズするための C# コード例です。このコードは、Swagger の有効化、UI のカスタマイズ、XML ドキュメントの読み込み、非表示 API のフィルタリング、およびドキュメントのキャッシュを設定します。

using Swashbuckle.Application;
using Swashbuckle.Swagger;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using System.Xml.Linq;

[assembly: PreApplicationStartMethod(typeof(SwaggerSetup), "Configure")]

namespace ApiProject
{
    public class SwaggerSetup
    {
        public static void Configure()
        {
            if (!PublicConfig.EnableSwagger) // Swagger を有効にするかどうか
            {
                return;
            }

            var assembly = typeof(SwaggerSetup).Assembly;

            GlobalConfiguration.Configuration
                .EnableSwagger(c =>
                {
                    c.SingleApiVersion("v1", "API ドキュメント");

                    // XML ドキュメントを含める
                    c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin/ApiProject.XML"));
                    c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin/Models.XML"));
                    c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin/Common.XML"));

                    // 非表示 API を除外するフィルタを適用
                    c.DocumentFilter<ApiHideFilter>();

                    // カスタム Swagger プロバイダーでドキュメントをキャッシュ
                    c.CustomProvider((defaultProvider) => new CachedSwaggerProvider(defaultProvider));
                })
                .EnableSwaggerUi(c =>
                {
                    c.DocumentTitle("API ドキュメント");

                    // カスタム JavaScript を注入して UI をローカライズ
                    c.InjectJavaScript(assembly, "ApiProject.Scripts.swagger_localization.js");

                    // API キー認証を有効化
                    c.EnableApiKeySupport("Authorization", "header");
                });
        }

        /// <summary>
        /// ドキュメントのキャッシュとコントローラーの説明を追加するカスタムプロバイダー
        /// </summary>
        public class CachedSwaggerProvider : ISwaggerProvider
        {
            private static readonly ConcurrentDictionary _cache = new ConcurrentDictionary();
            private readonly ISwaggerProvider _innerProvider;

            public CachedSwaggerProvider(ISwaggerProvider innerProvider)
            {
                _innerProvider = innerProvider;
            }

            public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
            {
                var cacheKey = $"{rootUrl}_{apiVersion}";
                if (!_cache.TryGetValue(cacheKey, out SwaggerDocument document))
                {
                    document = _innerProvider.GetSwagger(rootUrl, apiVersion);
                    document.vendorExtensions = new Dictionary { { "ControllerDesc", GetControllerDescriptions() } };
                    _cache.TryAdd(cacheKey, document);
                }
                return document;
            }

            /// <summary>
            /// XML ドキュメントからコントローラーの説明を取得
            /// </summary>
            /// <returns>コントローラー名と説明の辞書</returns>
            public static ConcurrentDictionary GetControllerDescriptions()
            {
                var descriptions = new ConcurrentDictionary();
                var xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin/ApiProject.XML");

                if (File.Exists(xmlPath))
                {
                    var doc = XDocument.Load(xmlPath);
                    foreach (var member in doc.Descendants("member").Where(m => m.Attribute("name")?.Value.StartsWith("T:") == true))
                    {
                        var name = member.Attribute("name")?.Value;
                        if (name != null && name.Contains("."))
                        {
                            var controllerName = name.Split('.').Last();
                            if (controllerName.EndsWith("Controller"))
                            {
                                var summary = member.Element("summary")?.Value?.Trim();
                                if (!string.IsNullOrEmpty(summary))
                                {
                                    var key = controllerName.Replace("Controller", "");
                                    descriptions.TryAdd(key, summary);
                                }
                            }
                        }
                    }
                }
                return descriptions;
            }
        }
    }

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class ApiHideAttribute : Attribute { }

    public class ApiHideFilter : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            foreach (var apiDescription in apiExplorer.ApiDescriptions)
            {
                if (apiDescription.GetControllerAndActionAttributes<ApiHideAttribute>().Any())
                {
                    var path = "/" + apiDescription.RelativePath.Split('?')[0];
                    swaggerDoc.paths.Remove(path);
                }
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class ApiGroupAttribute : Attribute
    {
        public string GroupName { get; }
        public string Description { get; }

        public ApiGroupAttribute(string groupName, string description)
        {
            GroupName = groupName;
            Description = description;
        }
    }
}

2. UI のローカライズ

Swagger UI を日本語にローカライズするための JavaScript ファイルです。このファイルはプロジェクトに「埋め込みリソース」として追加する必要があります。

/// <summary>
/// UI を日本語に翻訳
/// </summary>
var SwaggerLocalizer = (function () {
    var translationMap = new Map([
        ["Warning: Deprecated", "警告:非推奨"],
        ["Implementation Notes", "実装メモ"],
        ["Response Class", "レスポンスクラス"],
        ["Status", "ステータス"],
        ["Parameters", "パラメータ"],
        ["Parameter", "パラメータ"],
        ["Value", "値"],
        ["Description", "説明"],
        ["Parameter Type", "パラメータタイプ"],
        ["Data Type", "データタイプ"],
        ["Response Messages", "レスポンスメッセージ"],
        ["HTTP Status Code", "HTTPステータスコード"],
        ["Reason", "理由"],
        ["Response Model", "レスポンスモデル"],
        ["Request URL", "リクエストURL"],
        ["Response Body", "レスポンスボディ"],
        ["Response Code", "レスポンスコード"],
        ["Response Headers", "レスポンスヘッダー"],
        ["Hide Response", "レスポンスを非表示"],
        ["Headers", "ヘッダー"],
        ["Try it out!", "試してみる!"],
        ["Show/Hide", "表示/非表示"],
        ["List Operations", "操作を一覧表示"],
        ["Expand Operations", "操作を展開"],
        ["Raw", "生データ"],
        ["can't parse JSON. Raw result", "JSON を解析できません。生の結果"],
        ["Model Schema", "モデルスキーマ"],
        ["Model", "モデル"],
        ["apply", "適用"],
        ["Username", "ユーザー名"],
        ["Password", "パスワード"],
        ["Terms of service", "サービス利用規約"],
        ["Created by", "作成者"],
        ["See more at", "詳細はこちら:"],
        ["Contact the developer", "開発者に連絡"],
        ["api version", "API バージョン"],
        ["Response Content Type", "レスポンスコンテンツタイプ"],
        ["fetching resource", "リソースを取得中"],
        ["fetching resource list", "リソースリストを取得中"],
        ["Explore", "探索"],
        ["Show Swagger Petstore Example Apis", "Swagger Petstore サンプル API を表示"],
        ["Can't read from server. It may not have the appropriate access-control-origin settings.", "サーバーから読み取れません。適切な access-control-origin 設定がされていない可能性があります。"],
        ["Please specify the protocol for", "プロトコルを指定してください:"],
        ["Can't read swagger JSON from", "Swagger JSON を読み取れません:"],
        ["Finished Loading Resource Information. Rendering Swagger UI", "リソース情報の読み込みが完了しました。Swagger UI をレンダリング中"],
        ["Unable to read api", "API を読み取れません"],
        ["from path", "パスから"],
        ["Click to set as parameter value", "パラメータ値として設定するにはクリック"],
        ["server returned", "サーバーが返信"]
    ]);

    function translateElement(element) {
        $(element).html(translateText($(element).html()));
        $(element).val(translateText($(element).val()));
        $(element).attr('title', translateText($(element).attr('title')));
    }

    function translateText(text) {
        if (!text) return text;
        var trimmedText = text.trim();
        return translationMap.has(trimmedText) ? translationMap.get(trimmedText) : text;
    }

    function localizeUI() {
        if ($("#resources_container .resource").length > 0) {
            applyTranslation();
        }

        if ($("#explore").text() === "Explore" && $("#explore").length > 0) {
            setTimeout(localizeUI, 50);
        }
    }

    function applyTranslation() {
        $('[data-sw-translate]').each(function () {
            translateElement(this);
        });
    }

    function setControllerSummaries() {
        $.ajax({
            type: "GET",
            url: $("#input_baseUrl").val(),
            dataType: "json",
            success: function (data) {
                var summaryDict = data.ControllerDesc;
                $("#resources_container .resource").each(function () {
                    var id = $(this).attr("id");
                    if (id) {
                        var controllerName = id.substring(9);
                        var summary = summaryDict[controllerName];
                        if (summary) {
                            var option = $(this).children(".heading").children(".options");
                            if (option.children(".controller-summary").length > 0) {
                                option.children(".controller-summary").remove();
                            }
                            option.prepend('<li class="controller-summary" title="' + summary + '">' + summary + '</li>');
                        }
                    }
                });
            }
        });
    }

    return {
        init: function () {
            $("#logo").html("会社名").attr("href", "http://www.example.com");
            $('body').append('<style>.controller-summary{color:#10a54a !important;word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:250px;text-align:right;cursor:default;}</style>');
            setControllerSummaries();
            localizeUI();
        }
    };
})();

// ローカライズを実行
SwaggerLocalizer.init();

3. 設定の適用

上記のコードをプロジェクトに追加し、必要な NuGet パッケージ(Swashbuckle)をインストールします。`swagger_localization.js` ファイルは「埋め込みリソース」としてプロジェクトに追加してください。

4. ドキュメントへのアクセス

アプリケーションを実行し、以下の URL にアクセスすることで Swagger UI にアクセスできます。

http://[サイトのアドレス]/swagger

タグ: ASP.NET Web API Swagger Swashbuckle APIドキュメント

7月17日 21:51 投稿