zoukankan      html  css  js  c++  java
  • Swagger学习笔记

    什么是Swagger

    官网地址:https://swagger.io/docs/specification/about/

    Swagger是一套围绕OpenAPI规范构建的开源工具,可以帮助您设计,构建,记录和使用REST API。主要的Swagger工具包括:

    Swagger Editor - 基于浏览器的编辑器,您可以在其中编写OpenAPI规范。

    Swagger UI - 将OpenAPI规范呈现为交互式API文档。使用户可以直接在浏览器中尝试API调用。

    Swagger Codegen - 根据OpenAPI规范生成服务器存根和客户端库,支持超过40种语言为您的API 生成客户端库。

    什么是OpenAPI?

    OpenAPI规范(以前称为Swagger规范)是REST API的API描述格式。OpenAPI文件允许您描述整个API,包括:  

    ·每个端点上的可用端点(/users)和操作(GET /users,POST /users)

    ·操作参数每个操作的输入和输出

    ·验证方法

    ·联系信息,许可,使用条款和其他信息。

    ·API规范可以用YAML或JSON编写。该格式易于学习,并且对人类和机器都可读。完整的OpenAPI规范可以在GitHub上找到:OpenAPI 3.0规范

    一、Swagger生成在线接口文档

    创建一个WebApi项目,项目名Swagger,如图:

     

    通过Nuget安装Swashbuckle,会自动生成一个Swagger配置类SwaggerConfig.cs

     

    右键项目->属性->生成 勾选XML文档文件

     

    在SwaggerConfig类的EnableSwagger方法中配置xml文档文件地址,加入以下代码:

    c.IncludeXmlComments($"{AppDomain.CurrentDomain.BaseDirectory}/bin/Swagger.xml");

    此句代码包括下面提到要加入的代码在SwaggerConfig类中都有,只是都被注释了。

    运行项目,成功显示Swagger UI界面,如下图:

     

    二、汉化

    通过Swagger生成的在线接口文档功能显示的是英文,通过js实现汉化。在网上找了一个汉化脚本swagger.js,代码如下:

    'use strict';
    
    window.SwaggerTranslator = {
    
        _words: [],
    
     
    
        translate: function () {
    
            var $this = this;
    
            $('[data-sw-translate]').each(function () {
    
                $(this).html($this._tryTranslate($(this).html()));
    
                $(this).val($this._tryTranslate($(this).val()));
    
                $(this).attr('title', $this._tryTranslate($(this).attr('title')));
    
            });
    
        },
    
     
    
        setControllerSummary: function () {
    
     
    
            try {
    
                console.log($("#input_baseUrl").val());
    
                $.ajax({
    
                    type: "get",
    
                    async: true,
    
                    url: $("#input_baseUrl").val(),
    
                    dataType: "json",
    
                    success: function (data) {
    
     
    
                        var summaryDict = data.ControllerDesc;
    
                        console.log(summaryDict);
    
                        var id, controllerName, strSummary;
    
                        $("#resources_container .resource").each(function (i, item) {
    
                            id = $(item).attr("id");
    
                            if (id) {
    
                                controllerName = id.substring(9);
    
                                try {
    
                                    strSummary = summaryDict[controllerName];
    
                                    if (strSummary) {
    
                                        $(item).children(".heading").children(".options").first().prepend('<li class="controller-summary" style="color:green;" title="' + strSummary + '">' + strSummary + '</li>');
    
                                    }
    
                                } catch (e) {
    
                                    console.log(e);
    
                                }
    
                            }
    
                        });
    
                    }
    
                });
    
            } catch (e) {
    
                console.log(e);
    
            }
    
        },
    
        _tryTranslate: function (word) {
    
            return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
    
        },
    
     
    
        learn: function (wordsMap) {
    
            this._words = wordsMap;
    
        }
    
    };
    
     
    
    window.SwaggerTranslator.learn({
    
        "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": "响应Content Type",
    
        "fetching resource": "正在获取资源",
    
        "fetching resource list": "正在获取资源列表",
    
        "Explore": "浏览",
    
        "Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis",
    
        "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": "从路径",
    
        "server returned": "服务器返回"
    
    });
    
    $(function () {
    
        window.SwaggerTranslator.translate();
    
        window.SwaggerTranslator.setControllerSummary();
    
    });

    我把swagger.js放在了根目录下,swagger.js必须修改成嵌入的资源,如下图:

     

    最后在SwaggerConfig类的EnableSwaggerUi方法中加入以下代码:

    c.InjectJavaScript(thisAssembly, "Swagger.swagger.js");

    运行项目,汉化成功,如下图:

     

    三、相同操作出现多个方法报错

    此时如果再写一个带参Get方法,运行项目会报错,提示api/Values下有多个Get方法,如下图:

     

    在SwaggerConfig类的方法EnableSwagger中加入以下代码可以解决报错问题:

    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());

    运行项目,报错解决了,但是因为上面的代码是只取第一个方法,所以新写的方法不会出现在Swagger UI界面中,如下图:

     

    为了显示出新的Get方法,我修改了路由规则,路由中增加了方法名,如下图:

     

    重新运行项目,如下图:

     

    如果再写一个Get操作参数不一样的GetTest方法,这个方法也会被过滤掉,不会显示在Swagger UI界面。但是如果改成Post操作,是可以显示的,所以在Api接口方法中相同类型的操作要避免方法重名。如下图:

     

    四、Token

    Api接口肯定会用到Token验证,一般是把Token值放在请求头Header里,在请求参数里增加Token选项,在网上找了一段代码,类名我命名为HeaderTokenFilter ,如下:

        /// <summary>
    
        /// swagger 参数增加TOKEN选项
    
        /// </summary>
    
        public class HeaderTokenFilter : IOperationFilter
    
        {
    
            /// <summary>
    
            /// 应用
    
            /// </summary>
    
            /// <param name="operation"></param>
    
            /// <param name="schemaRegistry"></param>
    
            /// <param name="apiDescription"></param>
    
            public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    
     
    
            {
    
                if (operation.parameters == null)
    
                    operation.parameters = new List<Parameter>();
    
                var filterPipeline = apiDescription.ActionDescriptor.GetFilterPipeline(); //判断是否添加权限过滤器
    
                var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Instance).Any(filter => filter is IAuthorizationFilter); //判断是否允许匿名方法
    
                var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
    
                if (isAuthorized && !allowAnonymous)
    
                {
    
                    operation.parameters.Add(new Parameter { name = "TOKEN", @in = "header", description = "安全", required = false, type = "string" });
    
                }
    
            }
    
    }

    在SwaggerConfig类的方法EnableSwagger中加入以下代码:

    c.OperationFilter<HeaderTokenFilter>();

    运行项目,可以看到在方法请求参数中多了一个TOKEN参数,效果如下:

     

    在方法请求时输入Token值,我的Token验证值为了测试方便设置成了123456,效果如下:

     

    但是这样的话每次请求的时候都要给TOKEN参数赋值有点小麻烦,我们可以看到Swagger UI界面的最顶部有一个api_key,开启它就可以解决这个问题。

    在SwaggerConfig类的方法EnableSwagger中加入以下代码:

    c.ApiKey("TOKEN")
    .Description("API Key Authentication")
    .Name("TOKEN")
    .In("header");

    在SwaggerConfig类的方法EnableSwaggerUi中加入以下代码:

    c.EnableApiKeySupport("TOKEN", "header");

    运行项目,效果如下:

     

    五、控制器注释

    做完上述步骤基本就算完成了,但是我们也可以看到控制器的注释并没有显示,如果要显示控制器注释还需要增加代码了,在网上找了一段代码,类名我命名为SwaggerCacheProvider,如下:

        /// <summary>
    
        /// swagger显示控制器的描述
    
        /// </summary>
    
        public class SwaggerCacheProvider : ISwaggerProvider
    
        {
    
            private readonly ISwaggerProvider _swaggerProvider;
    
            private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
    
            private readonly string _xml;
    
            /// <summary>
    
            /// 
    
            /// </summary>
    
            /// <param name="swaggerProvider"></param>
    
            /// <param name="xml">xml文档路径</param>
    
            public SwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xml)
    
            {
    
                _swaggerProvider = swaggerProvider;
    
                _xml = xml;
    
            }
    
     
    
            public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
    
            {
    
     
    
                var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
    
                SwaggerDocument srcDoc = null;
    
                //只读取一次
    
                if (!_cache.TryGetValue(cacheKey, out srcDoc))
    
                {
    
                    srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
    
     
    
                    srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
    
                    _cache.TryAdd(cacheKey, srcDoc);
    
                }
    
                return srcDoc;
    
            }
    
     
    
            /// <summary>
    
            /// 从API文档中读取控制器描述
    
            /// </summary>
    
            /// <returns>所有控制器描述</returns>
    
            public ConcurrentDictionary<string, string> GetControllerDesc()
    
            {
    
                string xmlpath = _xml;
    
                ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
    
                if (File.Exists(xmlpath))
    
                {
    
                    XmlDocument xmldoc = new XmlDocument();
    
                    xmldoc.Load(xmlpath);
    
                    string type = string.Empty, path = string.Empty, controllerName = string.Empty;
    
     
    
                    string[] arrPath;
    
                    int length = -1, cCount = "Controller".Length;
    
                    XmlNode summaryNode = null;
    
                    foreach (XmlNode node in xmldoc.SelectNodes("//member"))
    
                    {
    
                        type = node.Attributes["name"].Value;
    
                        if (type.StartsWith("T:"))
    
                        {
    
                            //控制器
    
                            arrPath = type.Split('.');
    
                            length = arrPath.Length;
    
                            controllerName = arrPath[length - 1];
    
                            if (controllerName.EndsWith("Controller"))
    
                            {
    
                                //获取控制器注释
    
                                summaryNode = node.SelectSingleNode("summary");
    
                                string key = controllerName.Remove(controllerName.Length - cCount, cCount);
    
                                if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
    
                                {
    
                                    controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
    
                                }
    
                            }
    
                        }
    
                    }
    
                }
    
                return controllerDescDict;
    
            }
    
    }

    在SwaggerConfig类的方法EnableSwagger中加入以下代码:

    c.CustomProvider((defaultProvider) => new SwaggerCacheProvider(defaultProvider, $"{AppDomain.CurrentDomain.BaseDirectory}/bin/Swagger.xml"));

    运行项目,效果如下:

     

  • 相关阅读:
    HDU 2236 无题Ⅱ
    Golden Tiger Claw(二分图)
    HDU 5969 最大的位或 (思维,贪心)
    HDU 3686 Traffic Real Time Query System (图论)
    SCOI 2016 萌萌哒
    Spring Boot支持控制台Banner定制
    构建第一个Spring Boot程序
    Spring Boot重要模块
    Java fastjson JSON和String互相转换
    BCompare 4 Windows激活方法【试用期30天重置】
  • 原文地址:https://www.cnblogs.com/hsybs/p/11172109.html
Copyright © 2011-2022 走看看