ASP.NET CORE 第八篇 Swagger:API多版本控制,帶來的思考

原文作者:老張的哲學

1、什麼是版本控制

這個詞語大家已經不會陌生,平時開發的時候,一定會用到過 Git 、SVN 或者 VSS (這三個我都用過,Git 應該是最好的),這個就是源代碼的版本控制。

來句官方定義:版本控制是指對軟件開發過程中各種程序代碼、配置文件及說明文檔等文件變更的管理,是軟件配置管理的核心思想之一。

那今天我們說的,就是 api接口的版本控制,這個大家一定也都接觸到了,在我們使用的 swagger 中是這樣的:

image

2、api版本控制的好處

簡單來說,接口是APP的重要組成部分,數據是APP的核心,接口是連接APP和數據的紐帶(這裏的 APP 是廣義上的接口調用者)。

一般情況下,我們項目中會有大量的接口,再加上版本的變化,接口的升級,一個接口,可能會有很多個稍有差異的接口,這個時候接口如果維護的不好,錯一個就是一大片,那我們對 api 進行版本控制的好處有:

(1)有助於保護原有系統,不受影響,並及時修復問題
(2)可以實現用戶的私人定製,(我之前接觸過付費接口,可以這個意思)。
(3)快速迭代。

之前我在開發的時候,倒是沒有考慮過這個問題,都是想當然的以爲寫代碼只有一個版本,亦或者根本就沒有版本概念,昨天晚上在看有一個小夥伴問到了 swagger 中,如何進行版本控制( 然後我想了想,在平時的開發中,我開發的項目中還沒有遇到過版本控制,都是 web 項目+控制檯項目,有問題就直接修改,有 bug 直接覆蓋那種,從來沒有考慮過版本,但是既然咱們這個系列是基於 api 接口的,版本應該是要有的,而且相信以後如果開發 api 項目的時候,也會遇到這個問題。我就研究了下 swagger 的源碼,結合着網上的資料看了看,簡單的配置了下,是這樣的:

image

3、常見的版本控制有哪些?

通過上邊的配置,我自認爲很好的解決了這個問題,但是當我深入學習的時候,發現並不是,比如如何很好的調用不同版本的接口?,前端又如何對寫好的接口地址進行快速修改?等等多個問題引起我的思考,通過搜索資料,我總結了以下,常見的版本控制有以下幾個方案:

0、直接修改方法名,比如:/api/blog_v1,/api/blog_v2,/api/blog_v3... 雖然有時候也用,不過我直接 pass

1、通過路由控制,比如豆瓣:https://api.douban.com/v2/movie/in_theaters //本文重點說明,個人推薦,其他的大家可以參考博友文章
2、通過參數選擇,比如:http://localhost:58427/api/Values?api-version=2.0
3、通過http請求的 Headers 來控制,接口地址不變,下邊會說到
4、利用 content type 來控制

本文只是一個說明版本,並沒有把所有的方案都 code 出來,重點說了下路由控制,剩下的只是引導大家去思考這個問題,然後繼續學習,畢竟會一兩個方法就行了,平時開發中,使用的並不是很頻繁,有好的想法歡迎下邊留言。

一、在 swagger 中通過路由實現版本控制

1、註冊多個版本api

1、在 Blog.Core 項目下新建 SwaggerHelper 文件夾,然後添加 CustomApiVersion.cs 用來控制版本

image

2、在自定義API版本類中,添加枚舉版本號

 

    /// <summary>
    /// 自定義版本
    /// </summary>
    public class CustomApiVersion
    {
        /// <summary>
        /// Api接口版本 自定義
        /// </summary>
        public enum ApiVersions
        {
            /// <summary>
            /// v1 版本
            /// </summary>
            v1 = 1,
            /// <summary>
            /// v2 版本
            /// </summary>
            v2 = 2,
        }
    }

3、在項目啓動類 Startup.cs 中,配置服務,遍歷版本展示
在 ConfigureServices 方法內,修改 services.AddSwaggerGen 中的 c.SwaggerDoc 文檔如下:

 

//遍歷出全部的版本,做文檔信息展示
typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
{
    c.SwaggerDoc(version, new Info
    {
        // {ApiName} 定義成全局變量,方便修改
        Version = version,
        Title = $"{ApiName} 接口文檔",
        Description = $"{ApiName} HTTP API " + version,
        TermsOfService = "None",
        Contact = new Contact { Name = "Blog.Core", Email = "[email protected]", Url = "https://www.jianshu.com/u/94102b59cc2a" }
    });
});

4、修改 SwagerUI 調用配置
在 Configure 方法內,修改 app.UseSwaggerUI 如下:

 

app.UseSwaggerUI(c =>
{
    //之前是寫死的
    //c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
    //c.RoutePrefix = "";//路徑配置,設置爲空,表示直接在根域名(localhost:8001)訪問該文件

    //根據版本名稱倒序 遍歷展示
    typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
    {
        c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
    });
});

5、查看效果

 

image

現在已經實現了,在 swagger 中,進行多版本的展示,那要如何進行控制呢,請往下看。

2、對接口進行版本配置

1、剛剛我們已經創建好了多版本的接口文檔,那現在就需要配置接口api了
在 BlogController.cs 中新建一個 V2_Blogtest() 方法:

 

/// <summary>
   /// 獲取博客測試信息 v2版本
   /// </summary>
   /// <returns></returns>
   [HttpGet]
   //MVC自帶特性 對 api 進行組管理
   [ApiExplorerSettings(GroupName = "v2")]
   //路徑 如果以 / 開頭,表示絕對路徑,反之相對 controller 的想u地路徑
   [Route("/api/v2/blog/Blogtest")]
   public async Task<object> V2_Blogtest()
   {
       return Ok(new { status = 220, data = "我是第二版的博客信息" });

   }

這裏用到了 ApiExplorerSettings 特性,在mvc開發中,自帶的一個組管理。

爲什麼要配置路徑呢?是因爲多版本的情況下,可能會出現重名函數,這裏沒有體現出來,因爲使用的是 :V2_Blogtest ,下邊的文章中會說到,如果一定要重名,需要怎麼做。

2、這個時候查看效果,發現已經實現了我們文件開頭的效果

image

這個時候效果已經實現了,但是這麼寫顯然不是很方便,首先,我們的組名 GroupName 是寫死的 ”v2“,不利用拓展,然後呢,還需要再一次配置路由 Route,有小夥伴就發現了,既然這兩個都是特性,有沒有辦法重寫一個特性,把這兩個合併呢,欸?!就是這樣,請往下看。

3、自定義路由特性,實現路由+版本 雙控制

1、在根目錄的 SwaggerHelper 文件夾下,新建一個 CustomRouteAttribute.cs

 

/// <summary>
    /// 自定義路由 /api/{version}/[controler]/[action]
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class CustomRouteAttribute : RouteAttribute, IApiDescriptionGroupNameProvider
    {

        /// <summary>
        /// 分組名稱,是來實現接口 IApiDescriptionGroupNameProvider
        /// </summary>
        public string GroupName { get; set; }

        /// <summary>
        /// 自定義路由構造函數,繼承基類路由
        /// </summary>
        /// <param name="actionName"></param>
        public CustomRouteAttribute(string actionName = "[action]") : base("/api/{version}/[controller]/" + actionName)
        {
        }
        /// <summary>
        /// 自定義版本+路由構造函數,繼承基類路由
        /// </summary>
        /// <param name="actionName"></param>
        /// <param name="version"></param>
        public CustomRouteAttribute(ApiVersions version, string actionName = "[action]") : base($"/api/{version.ToString()}/[controller]/{actionName}")
        {
            GroupName = version.ToString();
        }
    }

2、對 api 接口進行設置

 

/// <summary>
 /// 獲取博客測試信息 v2版本
 /// </summary>
 /// <returns></returns>
 [HttpGet]
 ////MVC自帶特性 對 api 進行組管理
 //[ApiExplorerSettings(GroupName = "v2")]
 ////路徑 如果以 / 開頭,表示絕對路徑,反之相對 controller 的想u地路徑
 //[Route("/api/v2/blog/Blogtest")]

 //和上邊的版本控制以及路由地址都是一樣的
 [CustomRoute(ApiVersions.v2, "Blogtest")]
 public async Task<object> V2_Blogtest()
 {
     return Ok(new { status = 220, data = "我是第二版的博客信息" });

 }

瀏覽效果都是一樣的,這裏就不展示了,從這裏看出來,還是很方便的。

說到這裏,基於 swagger 的api接口版本控制已經說完了,採用的方法是路由控制,我個人感覺還是挺好的,當然文章的開頭也說到了,還是有其他的方法,這裏就簡單的其中一個,個人不是很推薦,但是大家可以看看。

二、同名接口的版本控制

在上邊咱們說到了,如果兩個版本的方法名一定要一直咋辦呢,重載大家肯定都知道,但是同一個 controller 接口方法肯定無論參數還是名稱全部都一樣,就連返回類型也一樣,所以不能重載,那我們應該怎麼辦呢?,請往下看。

1、 在 controller 文件夾下,新建兩個文件夾, v1、v2

2、然後添加相同的接口控制器 ApbController.cs,自定義即可

image

3、在兩個控制器中,添加相同的代碼

image

這樣就能實現同名方法的版本控制了。

三、其他不適用於 swagger 的接口版本控制方法

這些方法我本打算寫下來,發現不能通過 swagger 展示,會報錯,只能通過 postman 測試,所以對我來說不是很完美,這裏把博友的文章貼出來,大家可以自己看一下。

ASP.Net Core WebApi幾種版本控制對比
ASP.NET Core API 版本控制
Your API versioning is wrong, which is why I decided to do it 3 different wrong ways

 

發佈了51 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章