zoukankan      html  css  js  c++  java
  • 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": "apiteam@swagger.io"
        },
        "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 工作原理

    1. 使用NSwag解析json得到SwaggerDocument
    2. 使用RazorEngine将SwaggerDocument传入cshtml模板编译得到html
    3. 使用AngleSharp将html的文本代码提取,得到WebApiClient的声明式代码
    4. 代码美化,输出到本地文件

    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

  • 相关阅读:
    203. Remove Linked List Elements
    python练习小程序
    五十音练习小软件
    CocosCreator生命游戏
    一个swift下载程序
    用excel做一幅像素画
    翻译一篇SpiderMonkey GC的文章
    unity-3d拼图游戏
    NDK编译Python2.7.5
    git命令简图
  • 原文地址:https://www.cnblogs.com/kewei/p/9903851.html
Copyright © 2011-2022 走看看