每个开发人员都以某种方式接触到API 。 要么为一家大公司集成一个主要系统,或者使用最新的图形库生成一些精美的图表,要么直接与他喜欢的编程语言进行交互。 事实是,API无处不在! 它们实际上代表了当今Internet的基本构建块,在不同系统和设备之间发生的数据交换过程中扮演着重要角色。 从您手机上的简单天气小部件到您在网上商店中执行的信用卡付款,如果这些系统无法通过调用彼此的API相互通信,那么所有这些都是不可能的。

因此,随着连接到互联网的异构设备生态系统的不断发展,API提出了一系列严峻的挑战。 尽管它们必须继续以可靠和安全的方式运行,但它们还必须与所有这些设备兼容,从手表到数据中心内最先进的服务器。

REST来解救

用于构建此类API的最广泛使用的技术之一就是所谓的REST API。 这些API旨在提供异构系统之间通用且标准化的通信方式。 由于它们严重依赖于标准的通信协议和数据表示(例如HTTP,XML或JSON),因此很容易在大多数编程语言上提供客户端实现,从而使其与绝大多数系统和设备兼容。

因此,尽管这些REST API可以与大多数设备和技术兼容,但它们也必须不断发展。 演化的问题在于,有时您必须保持与旧客户端版本的回溯兼容性。

让我们建立一个例子。

让我们想象一个约会系统,在该系统中您具有一个用于创建和检索约会的API。 为简化起见,让我们想象一下约会对象和日期和来宾姓名。 像这样:

public class AppointmentDTO {public Long id;public Date date;public String guestName;
}

一个非常简单的REST API如下所示:

@Path("/api/appointments")
public class AppointmentsAPI {@GET@Path("/{id}")public AppointmentDTO getAppointment(@PathParam("id") String id) { ... }@POSTpublic void createAppointment(AppointmentDTO appointment) { ... }}

让我们假设这个简单的简单API可以正常工作,并且可以在允许预订和显示约会的手机,平板电脑和各种网站上使用。 到目前为止,一切都很好。

在某个时候,您认为开始收集有关您的约会系统的一些统计信息将非常有趣。 为了简单起见,您只想知道谁是预订次数最多的人。 为此,您需要将访客之间关联起来,并决定需要为每个访客添加唯一的标识符。 让我们使用电子邮件。 因此,现在您的对象模型将如下所示:

public class AppointmentDTO {public Long id;public Date date;public GuestDTO guest;
}public class GuestDTO {public String email;public String name;
}

因此,我们的对象模型稍有变化,这意味着我们将不得不在api上调整业务逻辑。

问题

尽管使API适应存储和检索新对象类型应该是一件容易的事,但问题是您当前的所有客户端都在使用旧模型,并且将继续这样做直到更新。 可以说您不必为此担心,客户应该更新到较新的版本,但事实是您不能真正地从头到尾进行更新。 始终会有一个时间窗口,您必须保持两个模型都运行,这意味着您的api必须具有复古兼容性。

这是您的问题开始的地方。

回到我们的示例,在这种情况下,这意味着我们的API将必须处理两个对象模型,并能够根据客户端存储和检索那些模型。 因此,让我们将guestName添加回我们的对象中,以保持与旧客户端的兼容性:

public class AppointmentDTO {public Long id;public Date date;@Deprecated //For retro compatibility purposespublic String guestName;public GuestDTO guest;
}

请记住,关于API对象的一条很好的经验法则是,永远不要删除字段。 添加新字段通常不会破坏任何客户端实现(假设它们遵循忽略新字段的良好经验法则),但是删除字段通常是噩梦之路。

现在,为了维护API兼容,有几种不同的选择。 让我们看一些替代方案:

  • 复制 :单纯。 为新客户端创建一种新方法,并使旧客户端使用相同的方法。
  • 查询参数 :引入一个标志来控制行为。 诸如useGuests = true之类的东西。
  • API版本控制 :在您的URL路径中引入一个版本,以控制要调用的方法版本。

因此,所有这些替代方案都有其优缺点。 尽管复制很简单,但它可以轻松地将您的API类变成一碗重复的代码。

可以(并且应该)将查询参数用于行为控制(例如,将分页添加到列表中),但是我们应避免将它们用于实际的API演变,因为这些参数通常是永久性的,因此您不希望使用对于消费者来说是可选的。

版本控制似乎是个好主意。 它提供了一种发展API的干净方法,它使旧客户端与新客户端分离,并为您在API寿命期间发生的各种更改提供了通用基础。 另一方面,它也引入了一些复杂性,特别是如果您在不同版本上有不同的调用时。 您的客户最终将不得不通过升级调用而不是API来自己管理API的演变。 就像您没有升级库到下一个版本,而是只升级了该库的某个类。 这很容易变成版本梦night……

为了克服这个问题,我们必须确保我们的版本涵盖整个API。 这意味着我应该能够使用/ v2来调用/ v1上的每个可用方法。 当然,如果v2上存在给定方法的较新版本,则应在/ v2调用上运行它。 但是,如果给定的方法在v2中没有更改,我希望可以无缝调用v1版本。

基于继承的API版本控制

为了实现这一点,我们可以利用Java对象的多态功能。 我们可以以分层的方式构建API版本,以便较新版本可以覆盖较旧版本的方法,而对未更改方法的较新版本的调用可以无缝地回退到其较早版本。

因此,回到我们的示例,我们可以构建一个新版本的create方法,以便API如下所示:

@Path("/api/v1/appointments")    //We add a version to our base path
public class AppointmentsAPIv1 { //We add the version to our API classes@GET@Path("/{id}")public AppointmentDTO getAppointment(@PathParam("id") String id) { ... }@POSTpublic void createAppointment(AppointmentDTO appointment) { //Your old way of creating Appointments only with names}
}//New API class that extends the previous version
@Path("/api/v2/appointments")
public class AppointmentsAPIv2 extends AppointmentsAPIv1 {@POST@Overridepublic void createAppointment(AppointmentDTO appointment) { //Your new way of creating appointments with guests}
}

因此,现在我们有2个有效的API版本。 尽管所有尚未升级到新版本的旧客户端将继续使用v1,并且不会看到任何更改,但您的所有新客户现在都可以使用最新的v2。 请注意,所有这些调用均有效:

呼叫 结果
GET /api/v1/appointments/123 将在v1类上运行getAppointment
GET /api/v2/appointments/123 将在v1类上运行getAppointment
POST /api/v1/appointments 将在v1类上运行createAppointment
POST /api/v2/appointments 将在v2类上运行createAppointment

这样,任何想要开始使用最新版本的使用者都只需将其基本URL更新为相应的版本,并且所有API将无缝转换为最新的实现,同时保持旧的不变。

警告

出于敏锐的眼光,这种方法立即引起了警告。 如果您的API由十分之几的不同类组成,那么即使您实际上没有任何更改,较新的版本也意味着将它们全部复制为较高版本。 这是一些可以自动生成的样板代码。 仍然很烦。

尽管没有快速的方法可以解决此问题,但是使用接口可能会有所帮助。 除了创建新的实现类之外,您还可以创建一个新的带路径注释的接口,并在当前的实现类中对其进行实现。 尽管您将必须为每个API类创建一个接口,但它有点干净。 它有一点帮助,但仍然是一个警告。

最后的想法

API版本控制似乎是当前的热门话题。 存在许多不同的观点和意见,但似乎缺乏标准的最佳实践。 尽管本文并非旨在提供这样的内容,但我希望它有助于实现更好的API结构并有助于其可维护性。

最后要说的是罗伯托·科尔特斯 ( Roberto Cortez)鼓励并允许将此帖子发布在他的博客上。 这实际上是我的第一篇博文,因此请加载大炮并随意开火。 :)

翻译自: https://www.javacodegeeks.com/2015/03/rest-api-evolution.html

REST API的演变相关推荐

  1. rest api_REST API的演变

    rest api 每个开发人员都以某种方式接触到API . 要么为一家大公司集成一个主要系统,或者使用最新的图形库生成一些精美的图表,要么直接与他喜欢的编程语言进行交互. 事实是,API无处不在! 它 ...

  2. 图形学书籍 Real-Time Rendering 3.4 可编程着色和 API 的演变(根据谷歌翻译修改)

    3.4 The Evolution of Programmable Shading and APIs 可编程着色和 API 的演变 The idea of a framework for progra ...

  3. java api 设计_Java API设计实践

    使你的API在模块化和非模块化Java环境中都可用 在优锐课的java学习分享中,对微服务有了更深层次的新概念.关于API设计实践一点就通了. 介绍 了解设计Java API时应应用的一些API设计实 ...

  4. java nio的演进_Java接口的防御性API演进

    java nio的演进 API的发展绝对是不平凡的. 只有少数几个需要处理的事情. 我们大多数人每天都在使用内部专有API. 现代IDE附带了很棒的工具,可以分解,重命名,上拉,下推,间接,委托,推断 ...

  5. Java接口的防御性API演进

    API的发展绝对是不平凡的. 只有少数几个需要处理的事情. 我们大多数人每天都在使用内部专有API. 现代IDE附带了很棒的工具,可以分解,重命名,上拉,下推,间接,委托,推断,泛化我们的代码伪像. ...

  6. 4.6 W 字总结!Java 11—Java 17特性详解

    作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...

  7. java默认代码地址_Java 8默认方法可能会破坏您的(用户)代码

    java默认代码地址 乍一看, 默认方法为Java虚拟机的指令集带来了一个很棒的新功能. 最后,库开发人员能够开发已建立的API,而不会对其用户代码造成不兼容性. 使用默认方法,当将新方法引入该接口时 ...

  8. Java 8默认方法可能会破坏您的(用户)代码

    乍一看, 默认方法为Java虚拟机的指令集带来了一个很棒的新功能. 最后,库开发人员能够开发已建立的API,而不会对其用户代码造成不兼容性. 使用默认方法,当将新方法引入该接口时,任何实现库接口的用户 ...

  9. Angular 7 和 .Net Core 2.2——全球天气(第1部分)

    目录 介绍 设置Angular CLI环境 先决条件 npm包管理器 从Visual Studio 2017创建Asp.Net核心Web项目 使用Angular CLI创建天气客户端 天气信息REST ...

最新文章

  1. matlab导出jar包错误Error: An error occurred while shelling out to javac(erro code = 1)解决办法...
  2. Android之替换App桌面图标
  3. 论文浅尝 | WWW2020 - 知识图谱中的实体摘要:算法、评价和应用 (PPT)
  4. C++之 把字符串作为宏参数
  5. 检错码之奇偶校验编码
  6. bzoj 2216: [Poi2011]Lightning Conductor(DP决策单调性)
  7. 穿了好几个马甲,差点没认出来是二分查找
  8. [2018.07.17 T2] Palindromes
  9. Charles4.62破解版本下载
  10. 认识5G(一):5G 单天线阵面Type I码本(Type I Single Panel codebook)生成过程
  11. php begintransaction,PDO::beginTransaction用法详解
  12. 激光雷达简介及物体检测(一)
  13. java孢子进化_孢子的进化起源
  14. 如何使用 QEMU 中的虚拟串口
  15. win10此电脑默认7个文件夹(附+ OneDrive、Catch!)隐藏方法
  16. CoinCola可盈可乐研究院2月报 | 加密货币集体上涨
  17. Android打开系统设置界面
  18. 如何实现上传多个图片并依次展示_如何在一页PPT中插入多张图片,并保持其美感...
  19. 2015级移动本面向对象课程主页
  20. [原创]gsoap的基本使用方法『C++web服务工具包』

热门文章

  1. java生成验证码并进行验证
  2. 三条中线分的六个三角形_八年级数学上册:三角形已知两条边如何求第三边
  3. 公式冒号是什么意思_三角学中,这么一堆公式其实就说了2个事而已
  4. gpu超算算法_超算安装GPU-based软件 (以pytorch为例)
  5. 如何用JS实现音乐播放、暂停
  6. idea快速生成crud_Java / Spring:如何快速生成完整的Swagger文档CRUD REST API
  7. aws生态系统集成商_通过通用数据访问扩展AWS生态系统
  8. elk入门_ELK堆栈入门
  9. java rest框架_比较Java REST文档框架
  10. 递归算法和迭代算法_Java中没有递归的二进制搜索–迭代算法