只有累積,沒有奇蹟

2021年5月30日 星期日

[NETCore] ASP.NET Core 中加入 API 版本控制

前言
在開發 API 時可能會因為代碼調整或是架構的演進,相同的 API 接口可能會有新的版本出現,為了不影響舊的呼叫端程式邏輯運作,就需要在代碼中加上新舊版本的對應來解決 API 版本問題,或許為了解決 API 版本問題可以有很多種不同的解法,在 ASP.NET Core 中可以透過  Microsoft.AspNetCore.Mvc.Versioning  來解決此問題,這篇就來分享一下有關Microsoft.AspNetCore.Mvc.Versioning 套件的安裝與基本使用,若有問題或是錯誤的地方歡迎網路的高手大大給予指導

安裝
首先直接透過專案的代碼可以方便大家可以更快的了解,起手式先建立一個 ASP.NET Core API 專案來作示範
建立完專案之後第一步是開啟開啟 Nuget Package Mnage 輸入 Microsoft.AspNetCore.Mvc.Versioning  搜尋,安裝目前最新版的套件
或是透過 Nuget Package Console 輸入下列指令
Install-Package Microsoft.AspNetCore.Mvc.Versioning
安裝完畢之後到專案檔底下確認是否有安裝成功
<ItemGroup>    
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.1.3" />    
</ItemGroup>

設定 
接著開啟專案中 Startup.cs 的 ConfigureServices 加上下列代碼
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddApiVersioning(o => {
        o.ReportApiVersions = true;
        o.AssumeDefaultVersionWhenUnspecified = true;
        o.DefaultApiVersion = new ApiVersion(1, 0);
    });
}
簡單說明一下設定所代表的含意及意義

ReportApiVersions

支援在 API Response Header 中加入 API 支援的版本,讓呼叫端知道目前版本有哪些,舉例來說開啟設定後如下,可以看到目前 API 支援的版本有 1.0 及 2.0 兩種版本

AssumeDefaultVersionWhenUnspecified
當發送的請求未指定 api-version 版本號時,是否需要啟用預設版本號。如果設定為 false 也未指定版本耗時則會出現錯誤訊息 An API version is required, but was not specified.

DefaultApiVersion
預設 API 版本號碼

使用 URL Querystring 指定版本
在此框架中使用  ApiVersion  來區分不同版本 API,接著為了要測試不同版本 API 回傳與設定,在 Controller 中加入下列代碼來驗證
using Microsoft.AspNetCore.Mvc;

namespace NetCoreWebAPIVersion.Controllers
{
    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/[controller]")]
    public class ValuesController : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }

    [ApiController]
    [ApiVersion("2.0")]
    [Route("api/values")]
    public class Values2Controller : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }
}
當未指定 API 版本時候,會參考稍早在 startup 中的 AssumeDefaultVersionWhenUnspecified 與 DefaultApiVersion 設定,在此範例中預設為 1.0 版因此可以看到回傳 version 為 1.0

透過上列代碼,可以在 url 帶入 api-version 參數來指定版本,舉例來說要指定版本為 2.0 則帶入 localhost/api/values?api-version=2.0 

使用 URL Route 指定版本 
也支援使用 Route 指定版本號,可以在 Route 加上  Route("api/v{version:api-version}/[controller]  ,根據上述調整做些微調如下
namespace NetCoreWebAPIVersion.ControllersV2
{
    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class ValuesController : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }

    [ApiController]
    [ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/values")]
    public class Values2Controller : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }
}
使用方式就很簡單,指定 1.0 版本
指定 2.0 版本  
如果需求情境是希望版號加在 Header 中,讓 url 避免透漏過多資訊也乾淨些,則可以在 service 中使用  HeaderApiVersionReader 進行設定,詳細可以參考官網說明。

設定過期 (棄用) 版本
在某些情境下可能早期的 API 版本將不在支援,在此框架中就可以透過設定 Deprecated  讓使用端知道,
舉例來說,下列代碼在 controller 一共有 0.1、1.0以及 2.0 三個版本,其中設定 0.1 版將不在支援,因此在 ApiVersion 中定義 Deprecated = true
namespace NetCoreWebAPIVersion.ControllersV2
{
    [ApiController]
    [ApiVersion("0.1", Deprecated =true)]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class Values3Controller : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }

    [ApiController]
    [ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/[controller]")]
    public class ValuesController : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }

    [ApiController]
    [ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/values")]
    public class Values2Controller : ControllerBase
    {
        [HttpGet]
        public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
    }
}
在呼叫 API 的 Response Header 中就可以看到目前支援版本為 1.0 與 2.0 兩種,版本 0.1 已過期

不限版本
在一些通用的 API 接口是不需要受到版號設定的,例如 Health Check 等資訊,硬是加上版號會讓人使用上更為不便,在此情境可以加上  ApiVersionNeurtal  屬性達到效果,並從 API 版本控制中移除
[ApiVersionNeutral]
[Route("api/[controller]")]
[ApiController]
public class HealthCheckController : ControllerBase
{
    public string Get() => "OK";
}

感想
透過以上說明相信對於ASP.NET Core WebApi Version 設定與應用有基本了解,在微軟 GitHub 官方 aspnet-api-versioning 也提供 sample code 範例給開發者了解,也可以發現版本控管框架不只支援 ASP.NET Core 也支援 .NET Framework WebAPI,如果對於細節或是應用想了解更多的話,不坊可以到 GitHub 可以看到更多有興趣的項目,希望這篇介紹可以有幫助到有需要的朋友 :)
Sample Code Path : sampleCode/NETCoreWebAPIVersioning

參考
aspnet-api-versioning
API Versioning in ASP.net Core
ASP.NET Core Web API Versioning 的做法

0 意見:

張貼留言

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com