美团开放平台为整个美团提供了20+业务场景的凋谢API,为了使开发者可能疾速且平安的接入美团开放平台,美团开放平台提供了多种语言的SDK来进步开发者的接入效率。本文介绍了美团开放平台如何主动生成SDK代码的相干技术实现计划,心愿对大家可能有所帮忙或者启发。

1. 引言

美团开放平台对外提供了外卖、团购、配送等20余个业务场景的OpenAPI,供第三方开发者搭建利用时应用,是美团零碎与内部零碎通信的最重要平台。本文次要讲述开放平台如何通过技术手段主动生成反对接口参数富模型和多种编程语言的SDK,以进步开发者对接开放平台API的效率。

1.1 背景

美团开放平台将美团各类业务提供的扩大服务封装成一系列应用程序编程接口(API)对外开放,供第三方开发者应用。开发者可通过调用开放平台提供的OpenAPI获取数据和能力,以实现本身零碎与美团零碎协同工作的业务逻辑。以外卖业务场景为例,开发者能够在本人为外卖商户开发的利用中通过调用美团开放平台提供的API,提供外卖订单查问、接单、订单治理等一系列性能。如下图所示:

开放平台为开发者提供的OpenAPI以HTTP接口的模式提供。以平台提供的订单查问接口为例,对应的HTTP申请如下所示:

POST https://api-open-cater.meituan.com/api/order/queryByIdContent-Type: application/x-www-form-urlencoded;charset=utf-8appAuthToken=eeee860a3d2a8b73cfb6604b136d6734283510c4e92282&charset=utf-8&developerId=106158&sign=4656285a4c2493e279d929b8b9f4e29310da8b2b&timestamp=1618543567&biz={"orderId": "10046789912119"}Response:{  "orderId":"10046789912119",  "payAmount":"45.67",  "status":7,  ......,  "products":[{"pid":"8213","num":2,...,"price":"3.67"}{"pid":"6556","num":1,...,"price":"11.99"}]}

由上述示例能够看出,美团开放平台提供给开发者的接口契约较为简单,其中蕴含了业务规定简单及安全性要求低等起因。若开发者须要间接从0到1编码对接平台提供的HTTP API,须要关注通信协议、接口契约标准、认证标识传递和平安签名等细节,老本较高。随着业务的倒退,平台反对的OpenAPI数量在近两年增长约一倍,达到近1000个,平台经营和研发人员须要投入越来越多的精力去帮忙开发者解决接口对接过程中的疑难问题。因而,提供SDK以帮忙开发者进步开发对接效率,变得非常有必要。

1.2 SDK指标概述

SDK,英文名称为 Software Development Kit,即软件开发工具包,狭义上指辅助开发某一类软件的相干工具、文档和范例的汇合。在开放平台的场景,咱们为开发者提供的SDK应能为其屏蔽调用OpenAPI的通信协议、参数传递标准、接口根底契约(如工夫戳、平安签名)等细节,以升高其对接平台API所需的开发成本。具备基本功能的开放平台SDK的架构和功能模块如下所示:

从应用SDK的开发者角度来看,基于SDK封装的根底性能来编写调用开放平台接口的代码,大抵逻辑如下所示:

MeituanClient client = DefaultMeituanClient.builder(developerId, signKey).build();//设置申请参数MeituanRequest request = new MeituanRequest("/api/order/queryById");request.setParam("orderId","10046789912119");MeituanResponse response = client.invokeApi(req);if(response.isSuccess()) {  long price = (long)response.getField("price");  String phone = response.getField("customerPhone");  int orderStatus = (int)response.getField("status");  //实现业务逻辑} else {  log.warn("query order failed with response={}", response);  //解决接口调用失败的逻辑}

从上述代码能够看出,提供根底性能的SDK曾经可能为使用者提供较大的便当。相比从零开始编码对接OpenAPI,应用SDK能够帮忙开发者省去解决通信协议、公共参数搁置、平安签名计算和返回状态码解析的工作量。但开发者在编写代码设置API的业务参数字段的环节,仍需对照API文档一一手工填充字段名并按字段类型赋值,并且在获取API返回的业务字段时也需自主填充字段名并解析数据类型,存在较大的不便且易出错。

为解决此问题,咱们须要在SDK的能力上更进一步提供对参数富模型的反对,即为每个API提供模型化封装的申请参数和返回参数构造,让应用SDK的开发者能够更加专一于业务逻辑的开发。

在SDK退出参数富模型的反对后,从使用者的角度来看,须要编写的代码如下所示:

MeituanClient client = DefaultMeituanClient.builder(developerId, signKey).build();//设置申请参数QueryOrderRequest request = new QueryOrderRequest();request.setOrderId("10046789912119");//调用接口MeituanResponse<QueryOrderResponse> response = client.invokeApi(req);//解决接口返回if(response.isSuccess()) {  QueryOrderResponse orderResponse = response.getData();  long price = orderResponse.getPrice();  String phone = orderResponse.getCustomerPhone();  int orderStatus = orderResponse.getStatus();  log.info("query order finish, price={}, orderStatus={}", price, phone, orderStatus);} else {  log.warn("query order failed with response={}", response);  //解决接口调用失败的逻辑}

能够看出,参数富模型性能能够进一步缩小开发者应用SDK的复杂度。以Java语言版本为例,QueryOrderRequest和QueryOrderResponse两个富模型类中封装了API的申请参数和返回参数的所有字段名、字段类型和字段校验规定等信息,开发者可简略应用字段的getter和setter办法实现对字段的赋值和取值操作,大幅升高了了解老本和出错可能。

尽管在SDK中反对参数富模型性能,能够无效进步使用者的效率,但也会带来SDK的开发和保护成本增加。如果采纳纯人工的形式去开发保护SDK中反对的所有API的参数模型代码,须要投入的开发保护老本与SDK反对的编程语言数量和API数量呈正相关性,其老本公式为:

从上述公式能够看出,当SDK所需反对的API数量和编程语言数量达到肯定数量时,通过纯人工编码去开发和保护SDK的老本会十分高。须要通过技术手段主动生成和测试SDK中的绝大部分代码,以达到在老本可控的前提下,为开发者提供反对多种编程语言版本的富模型SDK的指标。

2. SDK主动生成技术详解

2.1 整体设计

要为开发者提供一个反对参数富模型性能的OpenAPI SDK,咱们须要实现以下次要性能:

  1. 通信协议封装:让开发者无需关注调用API的通信协议和通信逻辑。
  2. 接口根底契约封装:让开发者无需关注调用API的参数传递格局、工夫戳、平安签名、返回Code码解决等细节。
  3. 申请参数模型封装:让开发者便捷地设置API申请参数。
  4. 返回参数模型封装:让开发者便捷地应用API返回的数据。

其中,通信协议封装和接口根底契约封装是一次性工作,并且其逻辑是绝对稳固的。对于SDK所需反对的每一种编程语言,只需投入无限的老本开发一次对应代码逻辑,即可撑持SDK的整个生命周期。而要为平台凋谢的1000余个API提供反对多种编程语言的参数富模型性能,靠人工编写和保护代码是极其低效的,咱们思考通过代码主动生成技术,对SDK中的参数富模型代码进行自动化生成。

更进一步,在实现了参数富模型代码主动生成后,咱们能够通过继续集成(Continious Integration)和继续公布(Continuous Delivery)技术,将SDK的生成、测试和公布流程也尽可能地做到自动化。整体的SDK主动生成流程设计如下图所示:

实现了以上流程后,即可做到在开放平台的任意API的参数模型发生变化时,由零碎主动生成和公布最新版本的SDK供开发者应用。咱们将在下文详述如何通过代码主动生成、继续集成和继续公布等技术手段实现上述流程。

2.2 主动生成参数模型代码

咱们最终的指标是为开放平台的每个OpenAPI,主动生成供SDK应用的申请参数模型代码(Request类)、返回参数模型代码(Response类)和调用示例代码(Example),并且代码主动生成机制要反对SDK适配的多种编程语言。以Java和C#编程语言为例,咱们要生成的指标代码如下图所示:

从下面的示例中能够看出,在申请参数模型(Request类)中须要生成Request Path、鉴权配置、字段强类型定义、字段取值、赋值及校验逻辑等代码。在返回参数模型(Response类)中,须要生成接口返回的各个数据字段的强类型定义、取值逻辑及校验规定。调用示例代码则须要蕴含申请参数赋值、发动接口调用和解决接口返回数据等相干逻辑。

要达成上述指标,首先须要思考的是代码主动生成技术的选型,目前业界支流的代码生成技术分为以下几类:

  1. 基于模版编排生成代码:最原始最简略也是目前利用最宽泛的一种代码生成形式。包含后端MVC框架的Controller、Service、DAO层模式化代码一键生成,还有前端Vue CLI 和Create-React-App两款脚手架的代码生成,都属于此类。
  2. 基于可视化UI生成代码:目前市场上使用得很广的一门技术,也被称为代码可视化生成工具。从Eclipse的Web可视化编辑器,到.NET Framework提供的MVC,及Winform界面及控件代码可视化拖拽生成,到汽车行业宽泛应用的可视化原型搭建工具(主动生成C代码)都属于此类。在近几年比拟火的低代码平台(如aPaaS)中,通过可视化UI生成代码的技术也被大量应用。
  3. 基于代码语料生成代码:基于代码语料生产代码的前提是要有足够的语料,例如伪代码/两头语言/描述性代码模板,再基于一套生成规定去生成指标代码。常见的落地场景包含RPC框架中基于IDL(Interface description language,接口描述语言)主动生成多种编程语言的RPC Client和Service代码,以及IDE插件中的代码主动生成性能(例如Eclipse的telosys插件可通过DSL生成多种语言代码)。
  4. 基于人工智能技术生成代码:属于比拟前沿的技术领域,多和AI畛域的图像识别和机器学习技术联合。现有的一些典型案例包含:微软开发的可将手绘图转化HTML代码的智能化代码生成工具sketch2code,基于AI技术主动生成UI逻辑的teleporthq。

思考到开放平台SDK中,须要主动生成的OpenAPI参数富模型代码和调用示例代码均具备绝对较强的规则性和模式性,咱们抉择基于代码语料主动生成代码的技术路线。

基于代码语料主动生成代码须要“语料”+“规定”两个外围元素,咱们能够通过解析API元数据并联合畛域专用语言(DSL)作为语料模板,生成代码语料,再基于语料个性为不同的编程语言定制代码生成规定,最终将“语料”+“规定”输出代码生成器以实现指标代码的生成。整体流程如下图所示:

在上述流程中,首先关注作为代码语料生成数据源的API元数据,其来源于开放平台实现的零编码API网关底层保护的根底配置。开放平台网关基于API元数据配置化的技术,可做到零编码将业务服务的RPC接口转化为HTTP协定的API进行凋谢。其根本运行构造如下图所示:

作为驱动开放平台网关运行的外围数据,API元数据中蕴含了HTTP Method、URL、申请参数、返回参数等信息。在参数信息中,又以树形构造记录了每个参数字段的字段名、字段类型、字段形容、校验规定和示例值。咱们以“按订单id查问订单详情”的API为例,其元数据中和SDK生成相干的数据如下所示:

APIGroup:waimaiAPISubGroup:orderAPIName: order_query_by_idHTTP METHOD: POSTHTTP PATH: /api/order/queryByIdDescription: 按订单id查问订单详情Request  |- orderId LONG NOT_NULL 要查问的订单的id example:1000224201796844308Response  |- orderId  LONG NOT_NULL 订单id  example:1000224201796844308  |- price  LONG NOT_NULL 订单金额(单位为人民币“分”) example:3308  |- phone  STRING  顾客联系电话   example:"13000000002"  |- products  ARRAY<Product>  订单商品列表     |- pid  LONG  商品id   example:"13000000002"     |- name  String  商品名  example:"珍珠奶茶"     |- num  INTEGER  商品数量  example:1     |- price  LONG  商品单价   example:1199     |- properties  ARRAY<Property>  商品属性列表        |- name STRING 商品属性名  example:"甜度"        |- value STRING 商品属性值  example:"七分糖"     |- remark  STRING  商品备注  example:"请做常温的"  |- status  INTEGER  订单状态  example:7

以上信息足以撑持咱们为SDK生成参数富模型和调用示例代码。下一步咱们须要开始解决代码语料,并为最终的代码自动化生成做好筹备。不同编程语言所需的代码语料有所差别,但同一类编程语言(如Java和C#都是面向对象的编程语言)大致相同。

以生成Java SDK中的参数富模型代码为例,须要用到的代码语料蕴含两局部。第一部分为类的根本信息,由元数据解析器在解析API的元数据时生成,其蕴含的内容和具体生成形式如下表所示:

第二局部为语料模板,咱们以DSL(Domain Specific Language)作为两头语言加以形容,如下所示:

<@class className=className metaInfo=javaApiMeta baseClass=baseClass interfaces=interfaces classDesc=classDesc package=packageName importPackages=importPackages>    <#-- 动态字段   -->    <#if staticFields?? && (staticFields?size > 0) >        <#list staticFields as param>            <@staticField param=param/>        </#list>    </#if>    <#-- 字段   -->    <#if privateFields?? && (privateFields?size > 0) >        <#list privateFields as param>            <@field param=param/>        </#list>    </#if>   <#-- Getter/Setter -->    <#if privateFields?? && (privateFields?size > 0) >        <#list privateFields as param>            <@getterMethod param=param/>            <@setterMethod param=param/>        </#list>    </#if>        <#-- 动态字段Getter -->    <#if staticFields?? && (staticFields?size > 0) >        <#list staticFields as param>            <@getterMethod param=param/>        </#list>    </#if>    <#if javaApiMeta?has_content>        <@deserializeResponse metaInfo=javaApiMeta/>        <@serializeToJson metaInfo=javaApiMeta/>    </#if>    <#-- toString办法 -->    <#if privateFields?? && (privateFields?size > 0) >        <@toString className=className params=privateFields/>    </#if></@class>

有了上述的代码语料,咱们即可通过语言转换引擎生成Java代码。咱们将解析好的API元数据作为输出,执行基于DSL的语言转换引擎。语言转换引擎通过执行宏命令将要生成的代码类的根本信息在DSL语料模板中进行填充,最终失去Java编程语言的指标类及其从属类的代码。以生成Response类代码为例,代码生成的具体执行过程如下图所示:

Request和Response类中其余的getter办法、setter办法、类注解等元素的生成原理和步骤均和以上雷同,此处不再赘述。在DSL语料模板中所有的元素解决实现后,咱们即可失去供Java编程语言应用的申请参数类和返回参数类的残缺代码。

对于其余的编程语言(例如Python),咱们应用的API元数据和元数据解析逻辑和Java是统一的,不同点在于DSL语料模板和语言转换引擎。当须要对SDK新增一种编程语言的反对时,咱们只须要对目标语言建设DSL语料模板并提供相应的转换逻辑,即可反对该语言的申请参数类和返回参数类的代码主动生成。

2.3 主动生成API调用示例代码

通过同样的技术手段,咱们还能够主动生成每个OpenAPI的调用示例代码,并将示例代码展现接口文档中供开发者参考。

调用示例代码的生成的逻辑绝对参数模型代码更加简略。咱们应用API元数据中的类名和字段信息(元数据中也蕴含了每个字段的examle值,可用于在代码示例中生成字段赋值的逻辑)填入代码语料中,再执行语言转换引擎生成指标代码即可。以Java编程语言为例,用于生成API调用示例代码的DSL语料模板如下所示:

<#setting number_format="computer">MeituanClient meituanClient = DefaultMeituanClient.builder(10000L, "xxxxx").build();<#assign reqVarName = className?uncap_first/>${className} ${reqVarName} = new ${className}();<#if privateFields?? && (privateFields?size > 0)><#list privateFields as field>${reqVarName}.set${field.fieldName?cap_first}(${field.exampleValue!""});</#list></#if><#if javaApiMeta.needAuth>String appAuthToken = "xxxx";MeituanResponse<${javaApiMeta.responseClass}> response = meituanClient.invokeApi(request, appAuthToken);<#else >MeituanResponse<${javaApiMeta.responseClass}> response = meituanClient.invokeApi(request);</#if>if (response.isSuccess()) {<#if javaApiMeta.responseClass == "Void">    System.out.println("调用胜利");<#else>    ${javaApiMeta.responseClass} resp = response.getData();    System.out.println(resp);</#if>} else {    System.out.println("调用失败");}

在应用API元数据和代码语料模板执行基于DSL的语言转换引擎后,生成的API调用示例代码如下所示:

MeituanClient client = DefaultMeituanClient.builder(developerId, signKey).build();//设置申请参数OrderQueryByIdRequest request = new OrderQueryByIdRequest();request.setOrderId(1000224201796844308L);//调用接口MeituanResponse<OrderQueryByIdResponse> response = client.invokeApi(req);//解决接口返回if(response.isSuccess()) {  OrderQueryByIdResponse orderResponse = response.getData();  System.out.println(orderResponse);} else {  System.out.println("调用失败");}

能够看出,咱们生成的API调用示例代码能够为开发者呈现出每个申请参数赋值的示例逻辑,可无效升高开发者在对接API时的了解老本。后续咱们能够进一步优化DSL语料模板,在示例代码中减少对返回数据结构中各个字段的取值逻辑示范,以进一步升高开发者在解决API返回数据时的了解和开发成本。

2.4 继续集成和继续公布

搞定参数富模型代码和调用示例代码的主动生成后,下一步是通过继续集成和继续公布技术,确保开发者在任何时刻均能获取到最新版本的SDK。传统由人工编译、测试和上传公布SDK的模式,开发者失去SDK版本更新的周期短则数周,长则数月。咱们的指标是将这个周期缩短到分钟级别:当SDK的根底逻辑和API参数模型有任何变更产生时,通过继续集成和继续公布的能力,在数分钟内将蕴含此变更的新版本SDK公布给开发者应用。

咱们基于美团自研的流水线引擎来驱动SDK的继续集成和继续公布。流水线的执行能够看作是对生成SDK的“原材料”一步步加工,最终交付到线上的过程。先通过下图理解整体流程:

首先咱们监听可能导致SDK须要公布的变更,包含通过Binlog机制监听API元数据的变更,以及通过Git Hook机制监听SDK根底逻辑代码仓库Master分支的变更。一旦监听到有变更产生,通过触发器去触发SDK继续集成和公布流水线的运作。

流水线开始运作后,首先执行SDK构建组件,SDK构建组件会并发执行两个操作:

  1. 获取SDK根底逻辑代码(人工编写)并实现动态代码查看;
  2. 拉取API元数据并主动生成参数富模型代码。

以上两个操作实现后,执行代码合并和代码编译,将后果提交到流水线执行下一个步骤。接下来由自动化测试组件实现对SDK的单元测试和端到端自动化测试,通过后提交到流水线执行下一个步骤。最初由主动公布组件实现SDK的打包、上传、下载链接生成和版本信息生成等一系列操作,并最终将最新版本SDK公布到官网供开发者下载。

3. 结语

通过上述能力的建设,咱们买通了SDK主动生成的整个环节,以自动化的形式实现代码生成、构建、测试、集成、公布等一系列行为,最终实现了在低人力投入的前提下继续向开发者交付最新版本SDK的指标。

通过最近半年数据的比照,咱们能够看出开发者应用SDK后在接口对接环节遇到的疑难问题显著缩小。根本达到了咱们最后进步开发者接入效率,升高平台研发和经营解决工单老本的指标。

后续,咱们将会打算持续欠缺SDK的代码主动生成逻辑,并为SDK增加更多编程语言的反对,为接入美团开放平台的开发者提供更好的体验。

4. 写在前面

不久前,美团独立申报的智慧生存国家新一代人工智能凋谢翻新平台正式取得中华人民共和国科学技术部(以下简称“科技部”)批复。这是美团第一个国家级科研平台。

国家新一代人工智能凋谢翻新平台被称为“人工智能国家队”,是聚焦人工智能重点细分畛域,充分发挥行业领军企业的引领示范作用,无效整合技术资源、产业链资源和金融资源,继续输入人工智能外围研发能力和服务能力的重要翻新载体。此前,已有百度、阿里、腾讯等15家公司先后获批建设。本次美团胜利申报,标记着美团的科研创新能力取得了国家层面认可,达到“国家队程度”。

5. 本文作者

飞宏、照东、宇豪、王鸿等,均来自美团到店事业群/餐饮SaaS事业部。

浏览美团技术团队更多技术文章合集

前端 | 算法 | 后端 | 数据 | 平安 | 运维 | iOS | Android | 测试

| 在公众号菜单栏对话框回复【2021年货】、【2020年货】、【2019年货】、【2018年货】、【2017年货】等关键词,可查看美团技术团队历年技术文章合集。

| 本文系美团技术团队出品,著作权归属美团。欢送出于分享和交换等非商业目标转载或应用本文内容,敬请注明“内容转载自美团技术团队”。本文未经许可,不得进行商业性转载或者应用。任何商用行为,请发送邮件至tech@meituan.com申请受权。