从Swagger上的API首先到RAML上的Single Contract

图片

嗨%用户名%!

您可能知道什么是API,在您的项目中有多少取决于它们。 此外,我还相信您已经熟悉API的第一种方法,并且您知道Swagger及其开放API是帮助他遵循的一些最受欢迎的工具。

但是在本文中,我想首先讨论实现API的方法,从概念上讲与Swagger和Apiary提供的方法不同。 这个想法的头是单一合同的概念以及基于RAML 1.0实施该合同的可能性。

下切:

  • 首先简要介绍API的原理;
  • 单一合同 -引入概念,出现的先决条件,在OAS的基础上考虑实施该概念的可能性(Swagger);
  • RAML +批注+叠加作为Single contract的基础,示例;
  • RAML问题,开发人员的概念分歧;
  • 基于以上想法的SaaS服务的想法(上面的原型图片)。



从Swagger上的API首先到RAML上的Single Contract


在设计现代软件系统时,通常需要协调和开发接口以使其组件之间相互交互。 在过去的十年中,SPA和胖移动应用程序通过API与服务器交互已经获得了极大的普及和发展。 以前,交互式网站的开发是通过逐步编辑服务器端代码来生成HTML标记,然后再将其转移到客户端的浏览器中进行的,但是现在动态Web应用程序的开发已转向创建单个服务API和许多应用程序(包括SPA)的并行开发使用此API作为主要数据源。 这种方法使您可以更方便地共享任务,组织仅专注于特定技术的团队(吸引更多的专业专家),在最初阶段组织并行开发,还可以创建一个单点通信-API接口。

这样的单点沟通需要一个正式且明确的定义,该文档是API规范。 为了今天开发和记录API规范,使用了各种技术和语言,例如:OAS(Swagger),Apiary和RAML。

以下三点决定了API优先方法的性质:

  1. API应该是开发应用程序的第一个客户端接口;
  2. 首先,开发API规范,然后开发其客户端的软件部分;
  3. API的生命周期应与其文档的生命周期一致。

如果考虑基于上述内容的过程,那么API规范就处于开发过程的中心,组成系统并将该API用作交互网关的所有系统节点都是该API规范的客户端。 因此,系统的服务器部分可以被视为相同的客户端规范API,就像使用该API与之通信的任何其他节点一样。 应用程序域模型不必与API规范中描述的模型匹配。 引入了它们与客户端应用程序代码中的类结构或数据库架构结构可能的故意重合,而不是为了简化开发过程,例如在使用根据OAS规范的代码生成器时。 从逻辑上讲,以上内容可以在“ 单一合同”的定义下进行总结。 单一合同 -许多客户。

单一合约。 合同工具和库


单一合同一词不要求在本文中使用任何批评。 就此而言,它的应用是我个人的想法。
首先API的概念扩展到更通用的单一协定使我们不仅可以将API规范视为系统组件之间接口的形式描述,而且可以将其视为任何数量的外部库和工具用作配置源的单一协定 。 在这种情况下,这些工具和库可以与SPA或移动应用程序一起视为合同客户。 此类客户的示例包括:

  • 文档生成器
  • 模拟服务器API
  • 压力测试服务
  • 请求/响应验证库
  • 代码生成器
  • UI生成器

此类客户端的单一合同是单一配置文件和数据源。 合同工具仅基于从特定合同获得的信息而起作用。 显然,对于像模拟服务器API这样的异构客户端的全部功能,一个API描述是不够的,还需要其他元信息,例如,描述GET请求参数(资源ID)与服务器应返回的数据之间的关系,指向响应字段的提示以及用于组织分页的查询参数。 此外,将更详细地考虑该示例。 同时,必须存在特定工具的特定信息,并且该信息必须与主文档密不可分地维护,否则将违反单一合同的概念。

Swagger(OAS)作为单一合同描述工具


市场上现有的最流行的Swagger(OAS)和Apiary(Blueprint)允许您使用特殊语言描述HTTP API:基于YAML或JSON的开放API,基于Markdown的Blueprint,这使规范易于阅读。 大型开源社区还创建了许多工具和库。 Swagger目前已广泛分发,也许有人会说,它首先已成为API的事实上的标准。 许多外部系统都支持Swagger规范的导入,例如SoapUIReadme.ioApigee等。 此外,现有的SaaS Swagger HubApiary允许用户创建项目,上载或创建自己的规范,使用内置的文档生成器和模拟服务器以及发布链接以从外部访问它们。

Swagger及其OAS 3.0看起来非常自信,并且在大多数情况下,其描述API的功能(特别是简单)就足够了。 以下是Swagger的优缺点列表:

优点:

  • 清晰易读的描述语言;
  • 大型开源社区;
  • 许多官方和开源编辑器,生成器,库;
  • 核心开发团队的存在,不断致力于格式的开发和改进;
  • 规范的共享软件中心;
  • 详细的官方文件;
  • 低进入门槛。

缺点:

  • 模块化支持不足;
  • 缺乏基于其结构描述的自动生成的查询响应示例;
  • SmartBear产品(摇摇欲坠的作者)的稳定性差,以及开发人员对此的反应迟钝,常常会带来一些问题(观点完全基于个人使用经验和我们团队的经验)。

但是,不允许使用OAS来描述单一合同的主要限制是缺乏附加自定义元信息来描述目标工具/库的其他参数的能力。
因此,所有基于Swagger规范工作的工具都必须对可容纳基本格式的信息集感到满意。

例如,智能模拟api服务器的实现需要比规范文档所能提供的更多信息,这就是为什么Swagger Hub模拟API内置的功能仅能够基于从规范文档中获得的数据类型/结构生成假数据。 毫无疑问,这还不够,仅通过简单的API客户端即可满足这样的模拟服务器功能。

在我们公司中,在一个项目(React SPA + API服务器)的开发过程中,需要以下模拟服务器功能:

  • 模仿分页。 服务器不应响应列表请求返回currentPage,nextPage,pagesTotal字段的完全随机值,而应根据从客户端收到的页面值生成这些元极的值,从而模拟分页机制的实际行为;
  • 根据传入请求的特定参数生成包含各种数据集的响应主体;
  • 在假对象之间建立真实关系的能力: Bar实体的foo_id字段应引用先前生成的Foo实体。 这可以通过向模拟服务器添加幂等支持来实现。
  • 模仿各种授权方法的工作:OAuth2,JWT等

没有所有这些,与系统的服务器部分的开发并行地开发SPA是非常困难的。 并且,同时,由于上述原因,如果没有其他特定的元信息可以直接在API规范中存储并在模拟下一个端点时通知其所需的行为,则几乎无法实现这种模拟服务器。 可以通过以与独立OAS规范平行的配置的独立文件的形式添加所需的参数来解决此问题,但是在这种情况下,您需要分别支持这两个不同的来源。

如果根据这个原理,有不止一个模拟服务器具有在开发过程环境中工作的工具,那么我们将获得“动物园”工具,每个工具都有其自己的独特功能,被迫拥有自己独特的配置文件,这些文件逻辑上链接到基本API -规范,但实际上是分开放置并过着“自己的生活”。

图片

问题:在更改基本规范的版本后,通常会在完全不同的位置和格式中,开发人员将被迫维护所有配置的相关性。

以类似原理工作的一些服务示例:

  • SoapUI是用于测试REST和SOAP接口的系统。 支持从Swagger规范导入项目。 更改基本的Swagger规范时,基于API调用列表的项目配置将继续并行存在,并且需要手动同步。
  • 其他SmartBear产品;
  • Apigee是API生命周期管理服务。 它使用Swagger规范作为模板,并在此基础上初始化内部服务的配置。 也没有自动同步;
  • Readme.io是一项服务,使您可以基于Swagger规范创建漂亮的文档,并且具有一种机制,用于跟踪对基本规范的更改并通过在服务端更新项目配置来解决冲突。 当然,这需要开发此服务的不必要的复杂性。

您可以在此列表中添加许多其他服务,这些服务提供Swagger规范的集成功能。 它们中大多数的集成意味着通常会复制Swagger规范的基本结构,并随后自动完成本地配置字段,而不支持与基本规范的更改同步。

RAML,注释,覆盖


寻找一种排除先前提到的OAS限制的工具的愿望,使我们可以将规范视为所有客户端工具的单一合同,这使我们开始熟悉RAML语言。 关于RAML的文章足够多,您可以在例如https://www.infoq.com/articles/power-of-raml上阅读 。 RAML开发人员已尝试在其概念级别上为模块提供语言支持。 现在,每个公司或单个开发人员都可以在设计API时创建自己的或使用现成的公共词典,重新定义和继承现成的数据模型。 从1.0版开始,RAML支持5种不同类型的外部模块: include,library,extension,trait,overlay ,这些模块允许根据任务尽可能灵活地使用它们。

现在是时候讨论RAML的主要可能性了,由于尚未完全理解的原因,RAML在OAS和“蓝图-注释”中没有类似物。
RAML中的注释是将自定义元数据附加到基础语言结构的能力。
正是此RAML函数成为撰写本文的原因。

一个例子:

#%RAML 1.0 title: Example API mediaType: application/json # Annotation types block may be placed into external file annotationTypes: validation-rules: description: | Describes strict validation rules for the model properties. Can be used by validation library allowedTargets: [ TypeDeclaration ] type: string[] info-tip: description: | Can be used by Documentation generator for showing tips allowedTargets: [ Method, DocumentationItem, TypeDeclaration ] type: string condition: description: | Named example can be returned if condition is evaluated to true. Can be used by Intelligent mock server allowedTargets: [ Example ] type: string types: Article: type: object properties: id: type: integer title: string paragraphs: Paragraph[] createdAt: type: string (validation-rules): ["regex:/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?Z?/"] Paragraph: type: object properties: order: type: integer (validation-rules): ["min:0"] content: string (validation-rules): ["max-length:1024"] /articles/{articleId}: get: (info-tip): This endpoint is deprecated description: Returns Article object by ID responses: 200: body: application/json: type: Article 

用户注释结构本身必须在RAML中具有清晰的描述。 为此,使用了一个特殊的notificationTypes部分,该定义也可以从中取出到外部模块。 因此,可以以附加到RAML API基本定义的注释形式定义外部工具的特殊参数。 为了避免使用大量外部工具的大量注解使基本规范混乱,我们支持将它们转移到单独的文件( 覆盖 (以及扩展名 ),并按范围进行分类)的可能性。 这是关于RAML文档( https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md#overlays )中的叠加层的说法:
覆盖层添加或覆盖RAML API定义的节点,同时保留其行为,功能方面。 RAML API定义的某些节点指定API的行为:其资源,方法,参数,主体,响应等。 这些节点无法通过应用叠加层进行更改。 相反,其他节点(例如描述或注释)则解决了功能接口之外的问题,例如某种语言的以人为本的描述性文档,或用于自动化工具的实现或验证信息。 可以通过应用覆盖来更改这些节点。

覆盖对于从实现中分离接口特别重要。 覆盖层为需要严格控制的API行为方面(例如API提供者与其使用者之间的合同)启用了单独的生命周期,而对于需要极少控制的行为(例如以人为本或以实现为导向的方面则可能会有所发展)不同的节奏。 例如,无需更改API行为方面的任何方面,就可以实现添加用于测试和监视工具的挂钩,附加与API注册表相关的元数据,或提供更新或翻译的人工文档。 这些事情可以通过严格的版本和变更管理过程来控制。
换句话说,此功能使您可以“从谷壳中分离出谷物”,例如API规范的主要描述,从特定于使用该工具进行工作的特定工具的其他元信息中分离出来。 每个单独覆盖中的元信息以注释的形式“挂在”规范的各个块上。

基本结构示例:

 #%RAML 1.0 title: Phrases API mediaType: application/json types: Phrase: type: object properties: content: string /phrases: get: queryParameters: whoSaid: string responses: 200: body: application/json: type: Phrase 

重叠式广告:
 #%RAML 1.0 Overlay usage: Applies annotations for Intelligent mock server extends: example_for_article_2_1.raml annotationTypes: condition: description: | Named example can be returned if condition is evaluated to true type: string allowedTargets: Example /phrases: get: responses: 200: body: application/json: examples: firstExample: (condition): $whoSaid is Hamlet content: "To be, or not to be?" secondExample: (condition): $whoSaid is Homer Simpson content: "D'oh!" 

结果,实现单个合同成为可能:所有功能,行为和元信息都在一个地方存储和版本控制,合同工具(合同的客户)必须支持本规范中使用的注释。 另一方面,工具本身可以提出自己的注释要求,这些注释必须“挂在”规范上-这将在开发合同工具时提供更多的可能性。

下图描述了以上概念:

图片

在此方法的缺点中,可以挑出基本规范文件和每个叠加图的手动同步的高复杂性:更新基本规范的结构时,您需要在叠加图的结构中应用所需的更改。 当出现多个覆盖时,此问题将变得更加严重。

一个可能且最明显的解决方案是为现有的在线RAML编辑器https://github.com/mulesoft/api-designer开发一个特殊的编辑器或附加组件。 编辑区域保持不变,但是可以创建选项卡:每个新选项卡都是一个窗口,用于编辑分配给它的叠加层。 在主窗口中编辑规范的基本结构时,所有创建的选项卡中的结构也会更改,并且当检测到新结构与位于选项卡叠层中的现有注释不兼容时,会出现警告。 这种编辑器的更详细考虑是一个单独的主题,值得认真考虑。

现有发展


在寻找接近实现将注释用作描述元信息的方法的想法的现有解决方案时,发现了以下解决方案:

  • https://github.com/raml-org/raml-annotations存储库,其中包含由RAML开发人员社区批准的官方注释。 在当前版本中,仅OAuth2批注可用。 外部工具可以使用它们来获取元信息,以描述针对已开发的API规范的OAuth2实现的各个方面;
  • https://github.com/petrochenko-pavel-a/raml-annotations用户注释库@ petrochenko-pavel-a具有按应用程序区域的逻辑分组。 该项目更具实验性,但完美地说明了使用注释的想法。 最有趣的注释组:
    • AdditionalValidation.raml-用于描述用于规范模型验证的其他规则的注释。 例如,服务器库可以将它们用于根据RAML规范来验证查询。
    • mock.raml-基于RAML规范描述模拟服务器详细信息的注释;
    • logicalContexts.raml-指向RAML规范的各个声明的结构块的语义上下文的注释;
    • structure.raml-注释,阐明了单独的RAML实体在描述的域模型的整体结构中的作用;
    • uiCore.raml-基于RAML规范的UI生成工具可以使用的注释示例;

该存储库还包含实用程序类型的库,这些实用程序类型适合用作描述RAML规范的数据结构的原语。

RAML问题


尽管具有基本功能的功能,先进性以及大型软件制造商(cisco,spotify,vmware等)的关注,但如今的RAML仍然存在严重的问题,这些问题对于其成功的命运可能是致命的:

  • 小型零散的开源社区;
  • 主要的RAML开发人员无法理解的策略是mulesoft 。 该公司开发的产品只是现有基于OAS的解决方案(包括在Anypoint Platform中 )的副本,而不是创建强调RAML优于Swagger的服务的产品;
  • 第一段的结果:少量的开源库/工具;
  • 进入门槛高于OAS(这很奇怪,但是很多人都这样认为);
  • 由于UX / UI中存在大量错误和问题,因此完全不适合并拒绝用户的主要服务是RAML的入口点-https://anypoint.mulesoft.com/。

概念上的分歧。 第一个结论


社区内部在基本概念上存在矛盾。 有人认为RAML是模型定义语言 ,有人认为它是API定义语言,例如OAS或Blueprint(自称为RAML开发人员的人经常在各种注释中提到这一点)。 模型定义语言的概念将允许RAML规范内部描述域的域模型,而无需紧密绑定API资源描述的上下文,从而扩大了将规范与外部工具一起使用的选择范围(实际上,为存在此单一合同奠定了基础!)。 这是资源概念的定义,可以在网站readhat docs( http://restful-api-design.readthedocs.io/en/latest/resources.html上看到,顺便说一句,我建议每个人都阅读这份设计API的出色指南):
我们将描述可用资源类型 ,其行为及其关系的信息称为API的资源模型资源模型可以看作是应用程序数据模型的RESTful映射。
在RAML 应用程序数据模型中,这些是在类型块中声明的类型 ,而API资源模型就是在资源 RAML块中描述的类型。 因此,您必须具有描述此映射的能力。 但是RAML的当前实现只允许这种映射从1到1完成,也就是说,在资源API声明中使用“原样”类型。

我认为这是该语言的主要问题,其解决方案将使RAML超越API定义语言 ,成为完整的模型定义语言 :一种更通用的语言(而不是OAS或Blueprint),用于描述系统的单一合同,本质上是形式核心他们的许多组成部分。

上述情况使RAML成为了一个弱者,目前无法在与Swagger的比赛中获胜。 也许这就是为什么RAML的主要开发人员采取了严厉措施的原因https://blogs.mulesoft.com/dev/api-dev/open-api-raml-better-together/

单一合约RAML SaaS的想法


基于单一合约的概念,从托管基于OAS的Swagger规范API规范的想法,以及依靠RAML功能声明元信息和使用覆盖共享基本规范的想法开始,提出了针对基于RAML的托管和规范管理的替代SaaS解决方案的想法可能功能的数量和质量要超过Swagger集线器和养蜂场。

类似于Swagger集线器,这项新服务将通过提供在线编辑器来托管用户合同,并具有通过实时更新查看文档预览的功能。 主要区别应该在于服务中内置了合同插件目录,用户可以在其当前项目中安装其中的任何API规范。 对于安装,将需要实施插件文档中指定的必需的RAML注释。 将新插件添加到项目后,当您切换到项目时,将在代码编辑器窗口中添加一个新选项卡,编辑已安装插件的注释将变为可用。 基本规范的结构应在与插件相对应的所有选项卡中自动复制。 如果基本结构和已经存在的注释之间发生冲突,则应使用一种特殊的机制为其解决方案提供选项,或者自动解决它。

图片

从技术上讲,每个选项卡都是RAML覆盖的抽象,其中包含每个特定插件的注释。 这样可以确保该规范与任何支持RAML 1.0的工具兼容。

必须打开插件目录,以供开源社区进行扩展。 也可以实施付费插件,这可以作为开发新插件的激励。

可能的插件:支持大量注释以对其渲染进行灵活参数化的API文档,“智能”模拟服务器(来自上例),用于验证请求或代码生成的可下载库,用于移动应用程序的出站API请求的调试工具(缓存代理),负载测试通过注解,用于与外部服务集成的各种插件来设置流测试。

服务的这种想法相对于用于管理API规范的现有服务具有明显的优势,并且其实现为可能更改与API相关的任何外部系统的实现方式铺平了道路。

第二个结论


本文的目的不是要批评Swagger,Apiary或其他事实上的标准工具来开发API,而是要检查RAML提倡的设计规范方法与概念上的区别,尝试首先引入Contract的概念,并考虑基于RAML实施Contract的可能性。 另一个目标是希望吸引开发人员当之无愧的关注RAML,以进一步发展其社区。

官方网站RAML
松弛通道
规格书

谢谢您的关注。

Source: https://habr.com/ru/post/zh-CN419525/


All Articles