Swagger 導出API


Swagger 導出API

這算是在博客園的第一篇博客吧,之后發的應該也會同步到博客園上。

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

Swagger簡介

Swagger是一個開源軟件框架,可幫助開發人員設計,構建,記錄和使用RESTful Web服務。

其中,Swagger可以生成一個交互式的API控制台,以便於快速測試API。

從個人角度講,Swagger對於前后端分離的小團隊來說是非常有幫助的。尤其是像我們這種平時沒寫文檔習慣的人來說,Swagger能根據代碼自動生成文檔可謂是一大福音,再也不用被人追着問這API到底是怎么用的。

這里,我將會具體說下最近我使用Swagger的一些心得和體會,團隊的開發環境如下:

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

生成Swagger API 文檔

對於ASP.NET Core來說,生成文檔這一步還是相對容易的,且對代碼基本沒有侵入性。只需在Startup中配置一下即可,大致步驟基本如下:

添加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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM