首页 物流新闻 人人都是 API 设计者:我对 RESTful API、GraphQL、RPC API 的考虑

人人都是 API 设计者:我对 RESTful API、GraphQL、RPC API 的考虑

点击上方 " 云年代架构",  右上角 挑选“设为星标” 精品技能文章按时送上! 现在,咱们来一同讨论 API 的规划之道。我会抛出几个观念,欢迎讨论。 一、界说好的标准,现已成功…

点击上方

"
云年代架构", 

右上角
挑选“设为星标”

精品技能文章按时送上!



现在,咱们来一同讨论 API 的规划之道。我会抛出几个观念,欢迎讨论。

一、界说好的标准,现已成功了一大半

一般情况下,标准便是咱们约定俗成的标准,假如咱们都恪守这套标准,那么天然交流本钱大大下降。例如,咱们都期望从阿里的标准上面学习,在自己的事务中也界说几个范畴模型:VO、BO、DO、DTO。其间,DO(Data Object)与数据库表结构一一对应,经过 DAO 层向上传输数据源目标。而 DTO(Data Transfer Object)是长途调用目标,它是 RPC 服务供给的范畴模型。关于 BO(Business Object),它是事务逻辑层封装事务逻辑的目标,一般情况下,它是聚合了多个数据源的复合目标。那么,VO(View Object) 一般是恳求处理层传输的目标,它经过 Spring 结构的转化后,往往是一个 JSON 目标。


事实上,阿里这种杂乱的事务中假如不区分清楚  DO、BO、DTO、VO 的范畴模型,其内部代码很简单就紊乱了,内部的 RPC 在 service 层的基础上又增加了 manager 层,然后完成内部的标准一致化。可是,假如仅仅独自的域又没有太多外部依靠,那么,彻底不要规划这么杂乱,除非预期到或许会变得庞大和杂乱化。对此,规划进程中量体裁衣就显得特别重要了。

          
  1. GET / users # 查询用户信息列表

  2. GET / users / 1001 # 检查某个用户信息

  3. POST / users # 新建用户信息

  4. PUT / users / 1001 # 更新用户信息(悉数字段)

  5. PATCH / users / 1001 # 更新用户信息(部分字段)

  6. DELETE / users / 1001 # 删去用户信息

事实上,RESTful API 的完成分了四个层级。榜首层次(Level 0)的 Web API 服务仅仅运用 HTTP 作为传输办法。第二层次(Level 1)的 Web API 服务引入了资源的概念。每个资源有对应的标识符和表达。第三层次(Level 2)的 Web API 服务运用不同的 HTTP 办法来进行不同的操作,而且运用 HTTP 状况码来表明不同的成果。第四层次(Level 3)的 Web API 服务运用 HATEOAS。在资源的表达中包含了链接信息。客户端能够依据链接来发现能够履行的动作。一般情况下,伪 RESTful API 都是依据榜首层次与第二层次规划的。例如,咱们的 Web API 中运用各种动词,例如 get_menu 和 save_menu ,而真实意义上的 RESTful API 需求满意第三层级以上。假如咱们恪守了这套标准,咱们就很或许就规划出通俗易懂的 API。

留意的是,界说好的标准,咱们现已成功了一大半。假如这套标准是业界标准,那么咱们能够斗胆实践,不要忧虑他人不会用,只需把业界标准丢给他好好学习一下就能够啦。例如,Spring 现已在 Java 的生态中无足轻重,假如一个新人不明白 Spring 就有点说不过去了。可是,许多时分由于事务的约束和公司的技能,咱们或许运用依据榜首层次与第二层次规划的伪 RESTful API,可是它不必定便是落后的,欠好的,只需团队内部构成标准,下降咱们的学习本钱即可。许多时分,咱们企图改动团队的习气去学习一个新的标准,所带来的收益(投入产出比)甚微,那就因小失大了。

总结一下,界说好的标准的意图在于,下降学习本钱,使得 API 尽或许通俗易懂。当然,规划的 API 通俗易懂还有其他办法,例如咱们界说的 API 的姓名易于了解,API 的完成尽或许通用等。

二、讨论 API 接口的兼容性

API 接口都是不断演进的。因而,咱们需求在必定程度上习惯改变。在 RESTful API 中,API 接口应该尽量兼容之前的版别。可是,在实践事务开发场景中,或许跟着事务需求的不断迭代,现有的 API 接口无法支撑旧版别的适配,此刻假如强制晋级服务端的 API 接口将导致客户端旧有功用呈现毛病。实践上,Web 端是布置在服务器,因而它能够很简单为了适配服务端的新的 API 接口进行版别晋级,可是像 Android 端、IOS 端、PC 端等其他客户端是运转在用户的机器上,因而当时产品很难做到适配新的服务端的 API 接口,然后呈现功用毛病,这种情况下,用户有必要晋级产品到最新的版别才干正常运用。为了处理这个版别不兼容问题,在规划 RESTful API 的一种有用的做法是运用版别号。一般情况下,咱们会在 url 中保存版别号,并一起兼容多个版别。

          
  1. GET / v1 / users /{ user_id } // 版别 v1 的查询用户列表的 API 接口

  2. GET / v2 / users /{ user_id } // 版别 v2 的查询用户列表的 API 接口

风趣的是,GraphQL 供给不同的思路。GraphQL 为了处理服务 API 接口爆破的问题,以及将多个 HTTP 恳求聚合成了一个恳求,提出只露出单个服务 API 接口,而且在单个恳求中能够进行多个查询。GraphQL 界说了 API 接口,咱们能够在前端愈加灵敏调用,例如,咱们能够依据不同的事务挑选并加载需求烘托的字段。因而,服务端供给的全量字段,前端能够按需获取。GraphQL 能够经过增加新类型和依据这些类型的新字段增加新功用,而不会形成兼容性问题。

此外,在运用 RPC API 进程中,咱们特别需求留意兼容性问题,二方库不能依靠 parent,此外,本地开发能够运用 SNAPSHOT,而线上环境制止运用,防止产生改变,导致版别不兼容问题。咱们需求为每个接口都应界说版别号,确保后续不兼容的情况下能够晋级版别。例如,Dubbo 主张第三位版别号一般表明兼容晋级,只要不兼容时才需求改变服务版别。

关于标准的事例,咱们能够看看 k8s 和 github,其间 k8s 采用了 RESTful API,而 github 部分采用了 GraphQL。


  • https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/


  • https://developer.github.com/v4/

三、供给明晰的思想模型

所谓思想模型,我的了解是针对问题域笼统模型,对域模型的功用有一致认知,构建某个问题的实际映射,并区分好模型的鸿沟,而域模型的价值之一便是一致思想,明晰鸿沟。假定,咱们没有明晰的思想模型,那么也不存在对 API 的一致认知,那么就很或许呈现下面图片中的实际问题。

四、以笼统的办法屏蔽事务完成

我以为好的 API 接口具有笼统性,因而需求尽或许的屏蔽事务完成。那么,问题来了,咱们怎样了解笼统性?对此,咱们能够考虑 java.sql.Driver 的规划。这儿,java.sql.Driver 是一个标准接口,而 com.mysql.jdbc.Driver
则是 mysql-connector-java-xxx.jar 对这个标准的完成接口。那么,切换成 Oracle 的本钱就十分低了。

一般情况下,咱们会经过 API 对外供给服务。这儿,API 供给服务的接口的逻辑是固定的,换句话说,它具有通用性。可是,但咱们遇到具有相似的事务逻辑的场景时,即中心的骨干逻辑相同,而细节的完成略有不同,那咱们该何去何从?许多时分,咱们会挑选供给多个 API 接口给不同的事务方运用。事实上,咱们能够经过 SPI 扩展点来完成的愈加高雅。什么是 SPI?SPI 的英文全称是 Serivce Provider Interface,即服务供给者接口,它是一种动态发现机制,能够在程序履行的进程中去动态的发现某个扩展点的完成类。因而,当 API 被调用时会动态加载并调用 SPI 的特定完成办法。


此外,咱们还常常运用工厂办法+战略形式来屏蔽内部的杂乱性。例如,咱们对外露出一个 API 接口 getTask(int operation),那么咱们就能够经过工厂办法来创立实例,经过战略办法来界说不同的完成。其间,operation 便是详细的指令。










  1. public

    class

    TaskManager

    {






  2. private

    static

    final

    Logger
    logger
    =

    LoggerFactory
    .
    getLogger
    (
    TaskManager
    .
    class
    );






  3. private

    static

    TaskManager
    instance
    ;






  4. public

    Map

    Integer
    ,

    ITask

    taskMap
    =

    new

    HashMap

    Integer
    ,

    ITask
    ();






  5. public

    static

    TaskManager
    getInstance
    ()

    {






  6. return
    instance
    ;






  7. }






  8. public

    ITask
    getTask
    (
    int
    operation
    )

    {






  9. return
    taskMap
    本文来自网络,不代表快递资讯网立场。转载请注明出处: http://www.llaiot.com/logistics-news/3179.html

上一篇
下一篇

为您推荐