Swagger 导出API

Swagger 导出API

这算是在博客园的第一篇博客吧,以后发的应该也会同步到博客园上。前端

此前的博客地址: https://blog.mytyiluo.cnnode

Swagger简介

Swagger是一个开源软件框架,可帮助开发人员设计,构建,记录和使用RESTful Web服务。ios

其中,Swagger能够生成一个交互式的API控制台,以便于快速测试API。git

从我的角度讲,Swagger对于先后端分离的小团队来讲是很是有帮助的。尤为是像咱们这种平时没写文档习惯的人来讲,Swagger能根据代码自动生成文档可谓是一大福音,不再用被人追着问这API究竟是怎么用的。github

这里,我将会具体说下最近我使用Swagger的一些心得和体会,团队的开发环境以下:json

  • ASP.NET Core 2.1 (Visual Studio 2017 Community)
  • 微信小程序 (官方工具+Visual Studio Code)

生成Swagger API 文档

对于ASP.NET Core来讲,生成文档这一步仍是相对容易的,且对代码基本没有侵入性。只需在Startup中配置一下便可,大体步骤基本以下:axios

添加NuGet包

这里,我所使用的是Swashbuckle.AspNetCore,直接用VS的NuGet包管理器下载便可。小程序

NuGet-Swashbuckle.AspNetCore

而后在ConfigureServices中配置以下:后端

services.AddSwaggerGen(c =>
{
    // 定义文档
    c.SwaggerDoc("v1", new Info { Title = "Qincai API", Version = "v1" });
});

并在Configure中启用该Services:微信小程序

// 使用Swagger
app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "Qincai API v1");
});

随后运行,打开浏览器host/swagger便可看到所生成的API文档。

Swagger UI

若还有不清楚的,能够参考微软官方的文档

完成到这里,是否是发现你和图中生成的样子有点不太同样,好比说,为何没有注释,以及认证用的小锁,那这里咱们就须要进一步配置。

添加XML注释

若是你们有在VS中写C#经历的话,确定会对XML注释影响深入,经过简单的///就能够自动生成规范的注释格式。那这里,咱们的Swagger也正是利用了这些XML注释来标记对应的API。

首先,咱们须要启用VS中导出XML文档的功能,在项目属性中,生成 > 输出,勾选XML文档文件,并填写对应的路径,我所写的是项目根目录。

输出XML文档

而后再到以前的ConfigureServices中添加以下:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new Info { Title = "Qincai API", Version = "v1" });

    // file 是你在项目属性中配置的相对路径
    var filePath = System.IO.Path.Combine(AppContext.BaseDirectory, file);
    c.IncludeXmlComments(filePath);
});

从新生成,再运行,你能够看到Swagger中就对API以及参数添加上了注释。

添加认证功能

在实际开发中,咱们经常是须要给咱们的API添加上认证功能以免非法的访问,所以咱们也就须要给Swagger中的API标识上是否须要认证,而且添加提供Token的功能,以方便在Swagger的控制台中调试。

简单来讲,仍是在ConfigureServies中,配置以下:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new Info { Title = "Qincai API", Version = "v1" });

    var filePath = System.IO.Path.Combine(AppContext.BaseDirectory, file);
    c.IncludeXmlComments(filePath);

    // 定义认证方式
    c.AddSecurityDefinition("Bearer", new ApiKeyScheme
    {
        In = "header",
        Description = "请键入JWT Token,格式为'Bearer '+你的Token。",
        Name = "Authorization",
        Type = "apiKey"
    });

    // 网上为全局API添加认证参数的方法
    // c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> {
    //     { "Bearer", Enumerable.Empty<string>() },
    // });

    // 在过滤器中为须要认证的API添加对应参数
    // 过滤器的定义见下文
    c.OperationFilter<AuthorizationHeaderOperationFilter>();
});

这里值得说一下的是,网上广泛都是全局添加认证参数,致使一些不须要认证的API也被打上了标识,这在Swagger 控制台中影响倒不大,但在后续的导出API时就麻烦了,全部在这里,我使用自定义过滤器的方式来只为须要认证的API添加认证参数。

根据上文,咱们先定义一个AuthorizationHeaderOperationFilter类,它须要实现IOperationFilter接口,类定义以下:

/// <summary>
/// 判断是否须要添加Authorize Header
/// </summary>
public class AuthorizationHeaderOperationFilter : IOperationFilter
{
    /// <summary>
    /// 为须要认证的Operation添加认证参数
    /// </summary>
    /// <param name="operation">The Swashbuckle operation.</param>
    /// <param name="context">The Swashbuckle operation filter context.</param>
    public void Apply(Operation operation, OperationFilterContext context)
    {
        // 获取对应方法的过滤器描述
        // 应该也就是所添加的Attribute
        var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
        // 判断是否添加了AuthorizeFilter
        // 也就是[Authorize]
        var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
        // 判断是否添加了IAllowAnonymousFilter
        // 也就是[AllowAnonymous]
        var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);

        // 仅当须要认证且不是AllowAnonymous的状况下,添加认证参数
        if (isAuthorized && !allowAnonymous)
        {
            // 若该Operation不存在认证参数的话,
            // 这个Security将是null,而不是空的List
            if (operation.Security == null)
                operation.Security = new List<IDictionary<string, IEnumerable<string>>>();

            // 添加认证参数
            operation.Security.Add(new Dictionary<string, IEnumerable<string>>
            {
                { "Bearer", new string[] { } }
            });
        }
    }
}

从新生成后运行,应该就能够看到须要认证的API都带上了一把小锁。

注意事项

虽然说配置并不算难,但仍是须要注意一些地方。

  1. 注意写好XML注释

    以前也说了,Swagger的注释是根据XML文档生成的,反过来讲,若是你没写XML注释,Swagger上也就是不会有注释的。

    另外,在你启用XML文档输出以后,VS也会很贴心的为你把没有写XML注释的地方都标为Warning。╮(╯▽╰)╭,因此安心的把注释都补一遍吧。

  2. 为参数添加数据注解

    Swagger是支持部分数据注解的,好比[Required]之类的。

    结合[ApiController]自带的模型验证功能,岂不美哉。

  3. 将XML文档复制到输出目录

    若你在发布应用后发现XML不见了,那可能就是你没有为XML文档文件配置复制到输出目录的属性。

    打开资源管理器,右键对应的文件,咱们在属性中能够看到有复制到输出目录的属性,将其设置为始终复制就Ok。

    XML文档属性

以上就是我最近所用到的Swagger的一些功能。

导出微信小程序可用的API

在一开始也说了,使用Swagger的主要目的就是方便小团队的沟通,但事实上,由于咱们前端的人少(你们都是CSS鬼才),致使咱们开发新API的速度每每比前端进度快,没几天前端那边就须要更新一下API的库(将小程序的CallBack封装成Promise)。

所以,就有了根据Swagger自动生成Js可用的API文件的想法,其实想法的自己是来自于Abp项目的设计(真的很优秀),但出于一些方面的考虑,咱们姑且还没采用Abp。

随后,就是查找资料了,确实Swagger有这方面的支持,其中官方关于Js的库是彻底动态的,但惋惜不适用于小程序。而后,就发现了第三方的swagger-js-codegen,可用于生成静态的Js代码,且提供了自定义模板的功能。网上也很多基于这个库的其余模板,好比说axios之类的,但没有适用于微信小程序的,不过问题不大,模板是基于mustache的,动手撸就是了。

模板代码有点长就不在这里放出了,你们还请移步GitHub

这里我就简单说下大体思路,

模板自己是基于原来的nodejs模板改的,咱们所需作的就是将http请求部分的代码改成使用wx.request,以下简单的封装便可:

/**
* HTTP Request
* @method
* @name {{&className}}#request
* @param {string} method - HTTP 请求方法
* @param {string} url - 开发者服务器接口地址
* @param {object} data - 请求的参数
* @param {object} headers - 设置请求的 header ,默认为 application/json
*/
request(method, url, parameters, data, headers){
    return new Promise((resolve, reject) => {
        wx.request({
            url: url,
            data: data,
            header: headers,
            method: method,
            success: res => {
                if(res.statusCode >= 200 && res.statusCode <= 299) {
                    resolve(res.data)
                } else {
                    reject(res)
                }
            },
            fail: e => reject(e)
        })
    })
}

对应method的话,基本没怎么改,只根据微信小程序全部参数都是传递给data,作了点简化。

对于认证部分,根据咱们本身的需求,换成了这样的实现:

new Promise((resolve, reject) => {
    this.authenticate()
    .then(token => {
        headers['Authorization'] = 'Bearer ' + token;
        resolve(this.request('{{method}}', domain + path, parameters, data, headers))
    })
})

其中this.authenticate是由外部传入的function,返回一个包含TokenPromise

导出后,在小程序中的使用就相似于:

import API from './api.js'

api = new API('http://localhost:5000')
api.setAuthenticate(function () {
    return new Promise((resolve, reject) => {
        // 你的认证逻辑
        resolve(token)
    })
})

而后,就能够开心地调用各类方法了。

最后,再放一遍Demo的连接:https://github.com/yiluomyt/swagger-wxopen-codegen-template,发现有问题欢迎提Issue。

相关文章
相关标签/搜索