我们有2个独立的产品需要通过Web服务相互通信。 支持API的自动化的最佳实践是什么?
我从2004年开始this article声称没有实际标准,只有最佳做法。更好的解决方案?你如何解决WS版本问题?
class SystemAClient{
SystemBServiceStub systemB;
public void consumeFromB(){
SystemBObject bObject = systemB.getSomethingFromB(new SomethingFromBRequest("someKey"));
}
}
class SystemAService{
public SystemAObject getSomethingFromA(SomethingFromARequest req){
return new SystemAObjectFactory.getObject(req);
}
}
版本1
class SystemAObject{
Integer id;
String name;
... // getters and setters etc;
}
第2版
class SystemAObject{
Long id;
String name;
String description;
... // getters and setters etc;
}
版本1
class SomethingFromARequest {
Integer requestedId;
... // getters and setters etc;
}
第2版
class SomethingFromARequest {
Long requestedId;
... // getters and setters etc;
}
class SystemBClient{
SystemAServiceStub systemA;
public void consumeFromA(){
SystemAObject aObject = systemA.getSomethingFromA(new SomethingFromARequest(1));
aObject.getDescription() // fail point
// do something with it...
}
}
class SystemBService{
public SystemBObject getSomethingFromB(SomethingFromBRequest req){
return new SystemBObjectFactory.getObject(req);
}
}
版本1
class SystemBObject{
String key;
Integer year;
Integer month;
Integer day;
... // getters and setters etc;
}
第2版
class SystemBObject{
String key;
BDate date;
... // getters and setters etc;
}
class BDate{
Integer year;
Integer month;
Integer day;
... // getters and setters etc;
}
版本1
class SomethingFromBRequest {
String key;
... // getters and setters etc;
}
第2版
class SomethingFromBRequest {
String key;
BDate afterDate;
BDate beforeDate;
... // getters and setters etc;
}
如果版本1 的系统A 客户端调用系统B 服务 版本2 >它可以失败:
SystemBObject
上遗漏的方法(getYear()
,getMonth()
,getDay()
)BDate
如果版本2 的系统A 客户端调用系统B 服务 版本1 >可能会失败:
BDate
上的未知类型SomethingFromBRequest
(客户端使用B版本1无法识别的较新B请求对象)SystemBObject
对象(getDate()
)上缺少方法可能会失败如果版本1 的系统B 客户端调用系统A 服务 版本2 >它可以失败:
SystemAObject
上输入错误匹配或溢出(已返回Long
,但预计为Integer
)如果版本2 的系统B 客户端调用系统A 服务 版本1 >可能会失败:
SystemARequest
上输入错误匹配或溢出(请求Long
而不是Integer
)Long
但服务返回Integer
并非在所有WS实现中兼容niksecarily)SystemAObject1
,SystemBRequest2
等,但缺少用于匹配源/目标版本的API 答案 0 :(得分:23)
我更喜欢Salesforce.com的版本控制方法。每个版本的Web服务都以以下格式获取不同的URL:
http://api.salesforce.com/{version}/{serviceName}
因此,您将拥有如下所示的Web服务URL:
http://api.salesforce.com/14/Lead
http://api.salesforce.com/15/Lead
依旧......
通过这种方法,您可以获得以下好处:
您总是知道您正在与哪个版本对话。
保持向后兼容性。
您不必担心依赖性问题。每个版本都有完整的服务。您只需要确保不要在调用之间混合版本(但这取决于服务的使用者,而不是您作为开发人员)。
答案 1 :(得分:4)
解决方案是避免对您的类型进行不兼容的更改。
以SystemBObject为例。您描述了此类型的“版本1”和“版本2”,但它们根本不是同一类型。对此类型的兼容更改仅涉及添加属性,而不是更改任何现有属性的类型。您假设的“版本更新”违反了这两个限制。
通过遵循一个guildeline,您可以避免所描述的所有问题。
因此,如果这是版本1中的类型定义
class SystemBObject{ // version 1
String key;
Integer year;
Integer month;
Integer day;
... // getters and setters etc;
}
然后,这不能是你在v2中的类型定义:
// version 2 - NO NO NO
class SystemBObject{
String key;
BDate date;
... // getters and setters etc;
}
...因为它已经消除了现有的领域。如果这是您需要进行的更改,则它不是新的“版本”,它是一种新类型,并且应该以代码和序列化格式命名。
另一个例子:如果这是您现有的v1类型:
class SomethingFromARequest {
Integer requestedId;
... // getters and setters etc;
}
...那么这不是该类型的有效“v2”:
class SomethingFromARequest {
Long requestedId;
... // getters and setters etc;
}
...因为您更改了现有属性的类型。
这些约束更详细地解释为Microsoft's Service Versioning article中与技术无关的方式。
除了避免不兼容的来源之外,您可以而且应该在类型中包含版本号。这可以是一个简单的序列号。如果您习惯于记录或审核消息,并且带宽和存储空间不是问题,则可能需要使用UUID扩充简单整数,以标识类型的每个唯一版本的实例。
此外,您可以通过使用宽松处理和将“额外”数据映射到“额外”字段来设计数据传输对象的向前兼容性。如果XML是您的序列化格式,那么当v1服务收到v2请求(more)时,您可以使用xsd:xmlAny或xsd:any和processContents =“lax”来捕获任何无法识别的架构元素。如果你的序列化格式是JSON,它的内容模型更开放,那么这是免费的。
答案 2 :(得分:3)
我知道现在已经很晚了,但我一直在深入研究这个问题。我真的认为最佳答案涉及另一个难题:服务中介。微软的托管服务引擎就是一个例子 - 我确信其他人也存在。基本上,通过更改Web服务的XML命名空间(包括版本号或日期,如链接文章所提到的),您允许中介将各种客户端调用路由到适当的服务器实现。 MSE的另一个(以及恕我直言,非常酷)功能是执行基于策略的转换的能力。您可以定义将v1请求转换为v2请求的XSLT转换,以及将v2响应转换为v1响应,从而允许您在不破坏客户端实现的情况下淘汰v1服务实现。
答案 3 :(得分:3)
我认为需要注意的是您的客户群,您是公开发布此服务还是仅限于一组已知代理?
我参与了后一种情况,我们发现通过简单的沟通/利益相关方解决这个问题并不困难。
虽然它只与您的问题间接相关,但我们发现基于兼容性的版本编号似乎运行良好。以A.B.C为例......