版本控制API


9

假设您有一个由API库支持的大型项目。该项目还附带了一个公共API,供最终用户使用。

有时您需要更改支持项目的API库。例如,您需要添加需要更改API的功能,新方法,或者需要更改传入或传自API的对象之一或这些对象之一的格式。

假设您还在公共API中使用这些对象,那么公共对象也会在您每次执行此操作时发生更改,这是不希望的,因为您的客户端可能依赖于API对象保持相同的解析代码才能正常工作。(咳嗽C ++ WSDL客户端...)

因此,一种潜在的解决方案是对API进行版本控制。但是,当我们说“版本” API时,听起来这还必须意味着对API对象进行版本控制以及为每个更改的方法签名提供重复的方法调用。因此,对于每个版本的api,我都会有一个普通的旧clr对象,这似乎也不可取。即使执行此操作,我也肯定不会从头开始构建每个对象,因为这将导致大量重复代码。相反,该API可能会扩展我们用于基础API的私有对象,但是随后遇到了同样的问题,因为如果不应该在公共API中使用附加属性,这些属性也将可用。

那么,这种情况通常适用于什么理智呢?我知道许多公共服务,例如Windows的Git都维护一个版本控制的API,但是我在构想一个支持该功能的体系结构而没有大量覆盖各种版本控制方法和输入/输出对象的重复代码时遇到了麻烦。

我知道,比如语义版本的尝试过程中把一些理智的时候应该发生的公共API休息。问题在于,如果对象之间的距离不远,似乎很多或大多数更改都需要破坏公共API,但是我发现没有重复代码的好方法。


1
I don't see a good way to do that without duplicating code-您的新API始终可以调用旧API中的方法,反之亦然。
罗伯特·哈维

2
可以使用AutoMapper进行救援,很遗憾,您需要每个合同的不同版本,不要忘记合同引用的所有对象都是该合同的一部分。结果是您的实际实现应具有其自己的模型的单个版本,并且需要将单个版本转换为各种合同版本。AutoMapper可以在这里为您提供帮助,并使内部模型比合同模型更智能。在没有AutoMapper的情况下,我使用了扩展方法来在内部模型和合同模型之间创建简单的转换。
吉米·霍法

是否有特定的平台/环境?(即DLL,REST API等)
GrandmasterB,2012年

.NET,带有MVC和Webforms ui,dll类。我们有一个rest API和soap API。
案例

Answers:


6

维护供第三方使用的API时,不可避免地需要进行更改。复杂程度取决于发生的更改的类型。这些是主要的方案:

  1. 现有API中增加了新功能
  2. API不推荐使用的旧功能
  3. API中的现有功能以某种方式更改

现有API的新功能

这是最容易支持的方案。向API添加新方法不应要求对现有客户端进行任何更改。对于需要新功能的客户端,这是安全的,因为它没有任何现有客户端的更新。

API不推荐使用的旧功能

在这种情况下,您必须与API的现有使用者进行沟通,以确保长期不支持该功能。在放弃对旧功能的支持(或直到所有客户端都升级到新功能)之前,必须同时保留旧的和新的API功能。如果是提供的库,则大多数语言都可以将旧方法标记为过时/不推荐使用。如果它是某种第三方服务,通常最好对旧/新功能使用不同的端点。

API中的现有功能以某种方式更改

这种情况将取决于更改的类型。如果不再需要使用输入参数,则只需更新服务/库即可忽略现在多余的数据。在库中,应该让重载的方法在内部调用需要较少参数的新方法。在托管服务中,端点将忽略额外的数据,并且它可以为两种类型的客户端提供服务并运行相同的逻辑。

如果现有功能需要添加新的必需元素,那么您的服务/库必须具有两个端点/方法。在客户端更新之前,您需要同时支持两个版本。

其他想法

Rather, the API is likely to extend the private objects we are using for our base API, but then we run into the same problem because added properties would also be available in the public API when they are not supposed to be.

不要通过您的库/服务公开内部私有对象。创建自己的类型并映射内部实现。这将允许您进行内部更改,并最大程度地减少外部客户端需要执行的更新量。

The problem is more that it seems like many or most changes require breaking the public API if the objects aren't more separated, but I don't see a good way to do that without duplicating code.

API是服务还是库,都必须在与客户端的集成点处保持稳定。您花费更多的时间来确定输入和输出应该是什么并将其作为单独的实体保存,这将为您节省很多麻烦。使API合同成为其自己的单独实体,并映射到提供实际工作的类。内部实现更改时节省的时间应能抵消定义额外接口所花费的额外时间。

不要将此步骤视为“重复代码”。虽然相似,但它们是值得创建的独立实体。尽管外部API更改几乎总是需要对内部实现进行相应的更改,但是内部实现更改不应总是更改外部API。

假设您要提供付款处理解决方案。您正在使用PaymentProviderA进行信用卡交易。稍后,您可以通过PaymentProviderB的付款处理器获得更高的汇率。如果您的API暴露了您类型的信用卡/账单地址字段,而不是PaymentProviderA的表示形式,则该API更改为0,因为该接口保持不变(希望无论如何,如果PaymentProviderB需要的数据不是PaymentProviderA所需要的,则您需要选择两者都支持,或者通过PaymentProviderA保持差价)。


感谢您提供非常详细的答案。您是否知道开放源代码项目的任何示例,我可能会仔细阅读这些示例以了解现有项目如何做到这一点?我想看一些具体示例,说明他们如何组织代码,使他们能够做到这一点,而不仅仅是将其各种POCO构造代码复制到各种版本对象中,因为如果调用共享方法,则必须将其拆分共享方法的版本,以便能够为版本对象编辑该对象。
案例

1
我“米不知道有任何好的例子了我的头顶,如果我有一段时间,这个周末我可以创建一个测试应用程序扔在GitHub上展示如何对这些事情可以实施。
菲尔·帕特森

1
棘手的部分是,从高层次上讲,有许多不同的方法来尝试最小化客户端和服务器之间的耦合。WCF有一个称为IExtensibleDataObject的接口,该接口使您可以从客户端传递合同中未包含的数据,并将其通过电线发送到服务器。Google创建了Protobuf,用于系统之间的通信(存在.NET,Java等的开源实现)。此外,还有许多基于消息的系统也可以工作(假设您的过程可以异步执行)。
菲尔·帕特森

显示您要删除的代码重复的特定示例(作为新的堆栈溢出问题)并查看社区提出了哪些解决方案,这可能不是一个坏主意。用一般术语很难回答这个问题。因此特定情况可能会更好。
菲尔·帕特森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.