zoukankan      html  css  js  c++  java
  • 基于OAS设计可扩展OpenAPI

    前言

    随着互联网行业的兴起,开发模式已逐步转换为微服务自治:小团队开发微服务,然后通过Restful接口相互调用。开发者们越来越渴望能够使用一种“官话”进行流畅的沟通,甚至实现多种编程语言系统的自动化交互。

    开放API战略(Open API Initiativev)于2017年1月发表声明,2月发布实现草案,经过反复讨论, 标准API规范OAS(OpenAPI-Specification)3.0版本在2017年6月诞生。

    本文通过对OAS 3.0的分析解读,希望抛砖引玉,和大家一起了解OAS如何定义一种机器和人都能够发现与识别的规范,使得OpenAPI消费者可使用最小数量的实现逻辑来理解远程服务。

    OpenAPI-Specification规范架构

    OAS 3.0架构中将OpenAPI赋予了以下8个模块的定义,其中黄色模块为必选字段,绿色模块为可选字段:

    各个主要模块工作流如下所示:

    以下重点说明用户获取OAS API信息的三个必选部分:

    1.API基本信息

    用户查询获取OpenAPI的基本定义及信息,涉及以下两个模块内容:

    openapi

    是否必选:必选

    对象类型:String

    类似于XML声明(<?xml version="1.0"?> ),用于设定文件应该使用哪一种规范进行解析。

    info

    是否必选:必选

    对象类型:Info Object

    这个模块主要提供API的元数据。

    以下为一个Info Object样例:

    title: Sample Pet Store App    #必须,应用名称 
    description: This is a sample server for apetstore.   #应用的描述 
    termsOfService: http://example.com/terms/      #应用的服务条款连接 
    contact:      #应用提供商的联系方式 
       name: API Support 
       url: http://www.example.com/support 
       email: support@example.com 
    license:   #应用所遵循的协议 
       name: Apache 2.0 
       url: http://www.apache.org/licenses/LICENSE-2.0.html 
    version: 1.0.1       #应用版本

    2.目标服务器信息

    用户查询获取服务器的基本定义及信息,涉及以下模块信息:

    servers

    是否必选:必选

    对象类型:[Server Object]

    这个模块主要提供和目标服务器的连接信息,如果这个模块没有定义url,根据规范会自动生成一个url为/的Server Object。

    例如:

    servers: 
    - url: https://development.gigantic-server.com/v1  #必选, 
      description: Development server   #非必选,url描述

    3.API路径及定义

    查询API具体参数,涉及OAS剩余的模块,本文主要介绍paths和components模块。

    paths

    是否必选:必选

    对象类型:Paths Object

    这个模块主要提供OpenAPI所在的目标服务器的连接信息,如果这个模块没有定义,根据规范会自动生成一个url为/的Server Object。通过多级定义,分别确定API的paths/method,并且通过$ref引用comonents模块中的定义,可以复用响应码等相关信息。对于携带body体的请求类型,requestBody可以提供example(或数组examples),这是非常灵活的(可以传入一个完整的例子,一个参考,甚至是一个URL的例子)。

    例如:

    /pets:        #URL 
         get:     #方法,get/post/.. 
                 description: Returns all pets .    #描述 
                         responses:         #响应模块 
                             '200':         #返回码为200,可以使用通配符定义响应 
                                     description: A list of pets.    #响应描述 
                                     content:           #Content字段 
                                         application/json: 
                                                     schema: 
                                                                 type: array  
                                                                         items: 
                                                                             $ref: '#/components/schemas/pet' #引用componets
    
    components
    
    是否必选:非必选
    
    对象类型:Components Object
    
    这个模块主要提供每个OpenAPI自定义的字段定义,这部分定义的对象往往被paths中具体API进行引用:
    
    −响应 responses
    
    −参数 parameters
    
    −示例 examples
    
    −请求体 requestBodies
    
    −标题 headers
    
    −链接 links
    
    −回调 callbacks
    
    −模式 schemas
    
    −安全体系 securitySchemes
    
    以下为一个Components Object样例:
    
    components: 
         schemas: #协议定义
             Category: 
                 type: object 
                 properties: 
                     id: 
                             type: integer 
                             format: int64 
                     name: 
                             type: string 
             Tag: 
                 type: object 
                 properties: 
                         id: 
                             type: integer 
                             format: int64 
                         name: 
                             type: string 
         parameters: #参数定义
             skipParam: 
                 name: skip 
                 in: query 
                 description: number of items to skip 
                 required: true 
                 schema: 
                     type: integer 
                     format: int32 
             limitParam: 
                 name: limit 
                 in: query 
                 description: max records to return 
                 required: true 
                 schema: 
                     type: integer 
                     format: int32 
         responses: #返回信息定义
             NotFound: 
                 description: Entity not found. 
             IllegalInput: 
                 description: Illegal input for operation. 
         GeneralError: 
             description: General Error 
             content: 
                 application/json: 
                         schema: 
                             $ref: '#/components/schemas/GeneralError' 
         securitySchemes: 
             api_key: 
                 type: apiKey 
                 name: api_key 
                 in: header 
         petstore_auth:  #认证定义
             type: oauth2 
             flows: 
                 implicit: 
                         authorizationUrl: http://example.org/api/oauth/dialog 
                         scopes: 
                             write:pets: modify pets in your account 
                             read:pets: read your pets

    如何使用OAS 设计可扩展的OpenAPI

    OpenAPI规范包含一组有关如何设计REST API的强制性准则,首推协议优先的方法,而非实现优先,因此需要首先设计API接口,然后实现协定接口的代码。

    如何实现一个优雅的API是一个非常具有挑战性的工作,开发者需要在庞大的后端系统的支持下,通过合适的方式将API暴露出去,除去单词拼写,路径设计等以外,设计优良的OpenAPI往往具有以下特性:

    单一职责

    单一职责是软件工程中一条著名的原则,实际在设计API时应确保每个API具有单一核心的职责,当某个API职责发生改变时不应该导致其他API发生故障和风险。OAS中不同的API可以在paths模块中引用多个schema,当我们设计新的API或者扩展原有API功能时,如果发现多个API多次引用相同schema,需重点审视每个API是否仍然保持单一职责。

    抽象API

    合适的抽象API 与业务无关的,更通用,而且方便扩展。 具体的API接口设计能解决特定的问题,但是在系统的扩展性和普遍适用性上则相应欠缺,因此需要针对特定的场景分析,避免over-designed(过度设计)和under-engineering(懒惰设计)。

    举个简单的例子,我们设计一个paths为/dog的API,那么这个API返回的是具体dog的相关信息,而如果我们进行抽象设计一个paths为/pet的API,将dog作为参数配置在components的parameters中,这样该API的扩展性进行了提升,后续扩展其他宠物比如cat的业务可以在不改变API路径的基础上进行开发,只需要更新component的parameters即可。

    收敛API

    提供给用户的OpenAPI最好支持批量数据处理,而不是让用户一次一次地调用。通过考虑多个API间的关联性,让用户体会到API的简洁性。举例来说,如果用户有可能在调用 API2之前需要API1的结果,那么API提供者应该把API1和API2进行包装。这会减轻用户的记忆负担,API收敛需要符合最少知识的原则,作为用户应该对他所使用的系统有最少的了解,而不是过多介入到系统的细节中,因此在设计API时候,在满足用户诉求的情况下,components模块字段越少越好。设计者往往容易在收敛API时候出现无法保证单一职责的原则的情况,好的设计需要在两者之间取得一个平衡,聚焦于最终的目的:让使用者快好省的用起来。

    扩展机制

    在设计API时需要考虑未来可扩展性,为后续API兼容历史API提供支持。一方面便于开发者自身增加功能,另一方面用户也能参与进来,共建API生态。通过设计定义OAS,可以方便的按照OAS架构设计出面向对象、扩展性良好的API。

    版本控制

    版本控制其实是扩展的一部分,鉴于大量项目在版本控制方面都做的比较糟糕,诸如随心所欲的版本命名、前后格式不一致的版本设定、没有规范的功能迭代,因此在大版本号不变的情况下,需要保障API向前兼容。当API的大版本号改动时,意味着API整体有大的改动,很可能不兼容之前的API,同时可以提醒用户需要查询API更新文档进行适配,否则用户可能在更新API之后出现各种各样难以预测的故障。反之,如果修改小版本号则意味着这是个向前兼容的优化升级,用户可以在例行更新中采用新的API。这种和用户约定好的默契,可以激发用户采用新版本的热情,而不是永远不升级依赖。

    面向扩展开发

    在通过OAS定义完相关信息之后,优雅的OpenAPI在开发过程中应着重思考API的可配置性,API的实现应该面向修改开放的,因此需要将相关诸如参数校验、字段长度等配置项进行抽取,在提供默认配置项的前提下可配置可修改,同时应当允许配置项的新增,例如引入java的可变参数类型等,这样当OAS文档进行修改时,可以尽可能的较少整体API实现的变动量。

    以上列举了优雅的OpenAPI所具有的部分特性,与其说OAS设计规范是一个强制的法则,不如说是一种引导式框架,开发者通过遵循规范从而实现高效的敏捷迭代。

    当完成OpenAPI的设计开发之后,我们需要将API托管到合适的平台上进行能力开放,优秀的平台减少API提供者的工作量,抽取公共能力使API提供者更加专注于业务功能开发。华为云的API网关集成了监控、流控、负载均衡等一系列功能,可以为开发者提供高性能、高可用的API 托管服务,实现个人、企业API能力的快速开放。

    关于API网关的详情,可以点击这里免费体验

    参考文献:

    《OpenAPI Specification》 :https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject

    《Microsoft REST API Guidelines》 :https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md

    《API 设计》 :https://docs.microsoft.com/zh-cn/azure/architecture/best-practices/api-design

    《从达标到卓越 —— API 设计之道》 :http://taobaofed.org/blog/2017/02/16/a-guide-to-api-design/

  • 相关阅读:
    桌面上嵌入窗口(桌面日历)原理探索(将该窗口的Owner设置成桌面的Shell 窗口,可使用SetWindowLong更改窗口的GWL_HWNDPARENT,还要使用SetWindowPos设置Z-Order)
    QQ截图时窗口自动识别的原理(WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx,RealChildWindowFromPoint)
    如何给开源的DUILib支持Accessibility(论述了DUILib的六个缺点,很精彩)
    从点击Button到弹出一个MessageBox, 背后发生了什么(每个UI线程都有一个ThreadInfo结构, 里面包含4个队列和一些标志位)
    Sessions, Window Stations and Desktops(GetDesktopWindow函数得到的桌面句柄, 是Csrss.exe创建的一个窗口)
    skip list
    理解对象模型图(Reading OMDS)
    Javascript与当前项目的思考
    Stub和Mock的理解
    https学习总结
  • 原文地址:https://www.cnblogs.com/middleware/p/9724675.html
Copyright © 2011-2022 走看看