写点什么

干货丨基于 OAS 设计可扩展 OpenAPI

  • 2019-10-22
  • 本文字数:4317 字

    阅读完需:约 14 分钟

干货丨基于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 信息的三个必选部分:

01 API 基本信息

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


openapi


是否必选:必选


对象类型:String


类似于 XML 声明( ),用于设定文件应该使用哪一种规范进行解析。


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.comlicense:   #应用所遵循的协议   name: Apache 2.0   url: http://www.apache.org/licenses/LICENSE-2.0.htmlversion: 1.0.1       #应用版本
复制代码

02 目标服务器信息

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


servers


是否必选:必选


对象类型:[Server Object]


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


例如:


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

03 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 能力的快速开放。


本文转载自公众号中间件小哥(ID:huawei_kevin)。


原文链接:


https://mp.weixin.qq.com/s/ZyswJu8pWxe1H0mdn_acVQ


2019-10-22 23:081797

评论

发布
暂无评论
发现更多内容

前端培训和自学的哪种方式更合适?

小谷哥

【Node.js】模块化学习

坚毅的小解同志

node.js 11月月更

【Node.JS 】创建基本的web服务器

坚毅的小解同志

node.js 11月月更

大数据培训学习后没有面试机会怎么办

小谷哥

【Node.JS 】服务器相关的概念

坚毅的小解同志

11月月更

【Node.JS】事件的绑定与触发

坚毅的小解同志

node.js 11月月更

【jquery Ajax】基础概念与使用教学

坚毅的小解同志

ajax 11月月更

盘点 | 云原生峰会重磅发布

阿里巴巴云原生

阿里云 云原生

云原生技术中台 CNStack2.0 正式发布

阿里巴巴云原生

阿里云 云原生 CNStack 云原生中台

Baklib知识分享|文档生命周期:确保您的文档产出效率

Baklib

kubernetes1.15极速部署prometheus和grafana

程序员欣宸

Kubernetes Prometheus 11月月更

java就业方向有哪些?

小谷哥

Linux 系统目录结构

芯动大师

Linux tar 11月月更 Linux目录

【Node.js练习】根据不同的url响应不同的html内容

坚毅的小解同志

node.js 11月月更

【Node.JS 练习】时钟案例

坚毅的小解同志

11月月更

OH应用程序集成AGC认证服务实现邮箱登录

白晓明

OpenHarmony AGC认证服务

曳影1520已成功运行Anolis OS!详聊平头哥在RISC-V软件生态的探索和实践 | 龙蜥技术

OpenAnolis小助手

操作系统 芯片 risc-v 龙蜥峰会 平头哥

【Node.js】模块的加载机制

坚毅的小解同志

node.js 11月月更

我服了!SpringBoot升级后这服务我一个星期都没跑起来!(下)

艾小仙

Java spring springbot

Node.JS 】http的概念及作用

坚毅的小解同志

node.js 11月月更

筑道与寻术:华为云与汽车产业的时代问答

脑极体

【Node.js】npm与包【万字教学~超超超详细】

坚毅的小解同志

node.js 11月月更

【Node.JS 】服务器相关的概念

坚毅的小解同志

【Node.JS 练习】考试成绩整理

坚毅的小解同志

node.js 11月月更

【Node.JS】buffer类缓冲区

坚毅的小解同志

node.js 11月月更

【Node.JS 】path路径模块

坚毅的小解同志

node.js 11月月更

【jquery Ajax】接口的学习与Postcode插件的使用

坚毅的小解同志

ajax 11月月更

大数据培训和自学怎么学习

小谷哥

云原生社区 Meetup 长沙站开始报名!

腾源会

云原生

西安java培训学习有哪些方法?

小谷哥

【Node.js练习】web服务器案例

坚毅的小解同志

node.js 11月月更

干货丨基于OAS设计可扩展OpenAPI_文化 & 方法_黄泽艺_InfoQ精选文章