swagger文件轉換為WebApiClient宣告式程式碼
1 swagger簡介
Swagger是一個規範且完整的框架,提供描述、生產、消費和視覺化RESTful Web Service。其核心是使用json來規範描述RESTful介面,另外有提供UI來檢視介面說明,並有一套生成不同語言的客戶端呼叫程式碼生成器。
1.1 對Api提供者
自頂向下
使用Swagger編輯器建立Swagger定義,然後使用Swagger程式碼生成工具生成伺服器實現。
自底向上
為已有的REST API建立Swagger定義。一般的,Api提供者都會選擇這種方式,比如在asp.net
裡整合swagger的支援,在寫好介面程式碼之後,訪問對應的swagger的訪問Uri地址,就可以得到swagger.json。例如:http://petstore.swagger.io/v2/swagger.json
{
"swagger": "2.0",
"info": {
"tags": null,
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"version": "1.0.0",
"title": "Swagger Petstore",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": " [email protected]"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"host": "petstore.swagger.io",
"basePath": "/v2",
"tags": [
...
1.2 對Api使用者
使用swagger UI
一些提供者的站點會提供swagger ui來檢視其swagger.json,例如:http://petstore.swagger.io/ 有了這些UI,自己手工編寫客戶端呼叫程式碼也非常簡單了。
使用Swagger Codegen
可以Swagger Codegen的將swagger.json逆向生成你需要的客戶端呼叫介面程式碼,本質上是使用了程式碼模板結合swagger.json描述來生成程式碼。在.net裡,有一個Nswag專案,可以將swagger.json生成使用HttpClient來請求介面的c#程式碼。但是這些程式碼的質量也比較差,比如以下程式碼的HttpClient的生命週期也就無法很好的維護。
/// <summary>Add a new pet to the store</summary>
/// <param name="body">Pet object that needs to be added to the store</param>
/// <exception cref="SwaggerException">A server side error occurred.</exception>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
public async System.Threading.Tasks.Task AddPetAsync(Pet body, System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/pet");
var client_ = new System.Net.Http.HttpClient();
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value));
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("POST");
PrepareRequest(client_, request_, urlBuilder_);
var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}
ProcessResponse(client_, response_);
var status_ = ((int)response_.StatusCode).ToString();
if (status_ == "405")
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new SwaggerException("Invalid input", (int)response_.StatusCode, responseData_, headers_, null);
}
else
if (status_ != "200" && status_ != "204")
{
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null);
}
}
finally
{
if (response_ != null)
response_.Dispose();
}
}
}
finally
{
if (client_ != null)
client_.Dispose();
}
}
2 WebApiClient.tools簡介
WebApiClient是.net平臺的一款RESTful宣告式的面向切面客戶端,其幾乎100%實現了swagger定義的規範,WebApiClient.tools.swagger旨在將swagger.json逆向生成符合WebApiClient的宣告式c#程式碼。
2.1 作用
使用原生HttpClient,你可能需要20行程式碼包裝呼叫一個介面;使用WebApiClient,你可能只需要一行程式碼來定義介面方法;使用WebApiClient + WebApiClient.tools.swagger,你一行程式碼都不用寫。
2.2 工作原理
- 使用NSwag解析json得到SwaggerDocument
- 使用RazorEngine將SwaggerDocument傳入cshtml模板編譯得到html
- 使用AngleSharp將html的文字程式碼提取,得到WebApiClient的宣告式程式碼
- 程式碼美化,輸出到本地檔案
2.3 樣例效果
介面程式碼
/// <summary>
/// Everything about your Pets
/// </summary>
[TraceFilter]
[HttpHost("https://petstore.swagger.io/v2/")]
public interface IPetApi : IHttpApi
{
/// <summary>
/// Add a new pet to the store
/// </summary>
/// <param name="body">Pet object that needs to be added to the store</param>
[HttpPost("pet")]
ITask<HttpResponseMessage> AddPetAsync( [Required] [JsonContent] Pet body );
/// <summary>
/// Update an existing pet
/// </summary>
/// <param name="body">Pet object that needs to be added to the store</param>
[HttpPut("pet")]
ITask<HttpResponseMessage> UpdatePetAsync( [Required] [JsonContent] Pet body );
...
模型程式碼
public class Pet
{
[AliasAs("id")]
public long? Id { get; set; }
[AliasAs("category")]
public Category Category { get; set; }
[AliasAs("name")]
[Required(AllowEmptyStrings = true)]
public string Name { get; set; }
[AliasAs("photoUrls")]
[Required]
public List<string> PhotoUrls { get; set; } = new List<string>();
...
3 相關資源
WebApiClient
github: https://github.com/dotnetcore/WebApiClient
WebApiClient.tools
github: https://github.com/xljiulang/WebApiClient.Tools
NSwag
github: https://github.com/RSuter/NSwag
RazorEngine
github: https://github.com/Antaris/RazorEngine