柴晓路 (fennivel@uddi-china.org)
Chief System Architect
2001年9月17日
本文是架构Web服务的系列文章的第五篇,以在前文中描述的应用实例为基础,详细定义了Catalog服务的API消息,全部API是使用SOAP完成调用和返回的,本文通过API的具体定义,详细介绍和演示了交互的数据结构和API消息结构的定义方法和相应模式,为读者在定义自己的Web服务接口时提供了实例的帮助和教程。
在本系列的前一篇文章中,对于给出的Case做了系统分析,并对系统作了模块划分,初步界定有如下在线服务组件:
- Catalog Service - 类别(Category)管理,产品(Product)管理,数据交换,数据备份等;
- Order Service - 接受订单,向其他接受订单的服务发送订单等;
- Feedback Service - 反馈信息(Feedback)管理,数据交换等。
由于这些服务显然必须有一个用户系统来支持,无论是因为安全性的考虑(有权限的才能做某些操作,还是因为事务的用户相关性(显然Order这样的服务不大可能脱离用户而实施)。因此我们需要增加一个在线服务Member Service,Membership的申请基本上可以依靠Web服务之外的流程完成,比如Web Application,因此Member Service的Web Service界面相对可以非常简化。所有这些在线组件服务需要提供的对外接口,我们的详细定义从下图开始:
Figure 1. API消息
本文所引用的资源主要包括两类,一类是Web服务的技术资源网站,包含了大量Web服务的技术信息,另一类是Web服务“stack"系列技术规范,他们是一个整体的技术体系,包括UDDI、SOAP、WSDL、XML等。本文的最后给出了这些资源的链接,有兴趣的读者可以通过这些资源链接找到所需的内容。
API概述
对于整个系统的API设计,其遵循的原则有这样几条:
简单性,由于这是一个对于公共开放的Web服务,它的API的设计首先应当是简单的,要被大量用户接受,要获得比较好的应用,那么API必须简单,没有哪个复杂难用的API会得到大家的广泛接受的,除非是普及率太广的系统,而目前我们要设计的Web服务是新系统,所以针对目前的应用实况,API必须简单。
可扩展性,作为更新频率较高,开放性较强的Web服务,其API应当具有很好的向后扩展性,当应内部需求的改变或外部需求的改变的需要时,API将根据新的商业逻辑发生变化,此时不应当将API从根本上推翻重建,而应当具备增量式的可扩展的能力。
兼容性,其实兼容性与可扩展性是互通的,API的兼容性指的就是向后兼容性,高版本的API应该具备对低版本API的兼容性,也就是说使用高版本API的Web服务,应当能支持使用低版本API的调用。
高效性,API应该在坚持简单性的前提下,兼顾高效性,当某些组合操作应用地非常频繁的时候,我们应当为这样的组合操作调用设计一个只需一次交互的单一入口调用,这样能够提升外部应用的效率,同时减轻Web服务的负载。
完备性,所谓完备性就是说整个API要覆盖所有需要对外公开的功能,这相对而言是最好实现的目标,只要设计阶段考虑得完备,就能达到完备性的要求。而且万一发现不完备的情况,修正起来也是相对容易的。
Catalog Service
- save_category: 保存category,在这个API调用中,包含了更新和新建的操作,同时category的迁移也可以通过这个API来完成。
- delete_category: 删除category,将指定category及其全部子元素从Catalog中删除。
- find_category: 在catalog中定位寻找category,可以通过多种方式,比如名称,比如关键字等。
- save_product: 保存product,在这个API调用中,同样可以包含更新、新建和迁移的操作。
- delete_product: 删除product,将指定product的信息从Catalog中删除。
- find_product: 在catalog中定位寻找product,可以通过多种方式,比如名称,比如所在的category,比如关键字等。
- get_categoryDetail: 获取category的完整信息,包括包含的所有category的简要信息和product的详细信息。
- get_productDetail: 获取product的完整信息。
- get_categoryInfo: 获取category及其所有子孙category和product的所有信息。
在定义这些消息之前,我们首先需要确定的是category和product这两个实体的XML描述格式。参照前文中的实体关系模型,我们可以将它们定义如下:
Category的具体描述格式:
<category categoryKey="…" parentCategoryKey="…">
<name>……</name>
<description>……</description>
</category>
|
Product的具体描述格式:
<product productKey="…" parentCategoryKey="…">
<name>……</name>
<description>……</description>
<compliantSpecBag />
<featureBag />
<parameterBag />
</category>
|
其中,compliantSpecBag、featureBag和parameterBag的具体格式分别如下:
<compliantSpecBag>
<specification specificationKey="……" /> *
</compliantSpecBag>
|
compliantSpecBag描述的是一种计算机产品遵循了哪些相关的业界标准。在这个聚集里面,specification这个元素可以出现多次,每一个条目分别表示其遵循了一种工业标准,比如一台娱乐型的便携式计算机可能就会遵循诸如USB1.0、IEEE1394等等的工业规范。
<featureBag>
<feature>……</feature> *
</featureBag>
|
featureBag描述的是一种计算机产品的重要特性。在这个聚集里面,feature这个元素可以出现多次,每一个条目使用字符串文本来描述某一种产品特性。比如一台娱乐型的便携式计算机可能的特性会包括"重量仅有2磅,厚度仅有1.9cm,超级便携"这样的特性描述。
<parameterBag>
<parameter> *
<keyName>……</keyName>
<keyValue>……</keyValue>
</parameter>
</parameterBag>
|
parameterBag描述的是一种计算机产品的相关技术参数。在这个聚集里面,parameter这个元素可以出现多次,每一个条目使用keyName和keyValue名值对来描述某一个技术参数。比如一台便携式计算机可能的技术参数会是TFT_Size10.1"。
在定义了核心的数据模型之后,我们就可以来分别定义具体的API消息了。
save_category
用于保存category的最新信息,使用这个API调用,可以完成对category的更新、新建和迁移的操作。
<save_category>
<authInfo>……</authInfo>
<category categoryKey="…" parentCategoryKey="…"> *
<name>……</name>
<description>……</description>
<category /> *
<product /> *
</category>
</save_category>
|
在上述的语法描述中,大家应该可以发现,save_category能够用于保存一棵或多棵完整的category树,而不光光是仅仅保存一个或多个category结点,这样的设计是为了高效性的设计目标而做的调整。
当整个消息中的任意一个category或product所属的标识自身实体的键值categoryKey或productKey为空,即表示这是一个新增的category或product,需要被插入到数据库中,在返回消息中,将回送这些元素的键值。
当消息中任意一个category或product的parentCategoryKey没有发生更改时,表明是要更新该元素的信息。而若parentCategoryKey发生更改的时候,表明该元素将从之前的由原有parentCategoryKey所标识的category结点下被迁移到由新的parentCategoryKey所标识的category结点下。当然如果包含了数据更新操作,同样会实施该数据更新操作。
细心的读者一定已经发现了在这个消息中,有一个authInfo元素,这是一个用于权限检验的授权令牌。在后面我将指明这个元素是如何获取并使用的。
save_category消息调用的返回是一个或多个完整的被接受的category信息,与提交的信息的差别就是仅有概要信息,没有相信信息,同时原先空着的键值都被填上Web服务所指派的键值。下面是一个返回消息的例子:
<result>
<category categoryKey="a01" parentCategoryKey="……">
<category categoryKey="a02" parentCategoryKey="a01" />
<category categoryKey="a03" parentCategoryKey="a01" />
<category categoryKey="a04" parentCategoryKey="a01" />
<product productKey="p01" parentCategoryKey="a01" />
<product productKey="p02" parentCategoryKey="a01" />
</category>
<category categoryKey="b01" parentCategoryKey="……">
<category categoryKey="b07" parentCategoryKey="b01" />
<category categoryKey="b08" parentCategoryKey="b01" />
<product productKey="p09" parentCategoryKey="b01" />
</category>
</result>
|
delete_category
用于删除category的API调用,能够将一个或多个category及其全部子元素从Catalog中删除。
<delete_category>
<authInfo>……</authInfo>
<category categoryKey="…" /> *
</delete_category>
|
在上述的语法描述中,大家应该可以发现,save_category能够用于删除一个或多个使用categoryKey标识的category。当一个category被删除时,其所有子元素(包括category子元素和product子元素)都将被删除。
delete_category消息调用的返回是一个或多个被实施删除的category信息的键值列表。
find_product
用于在某个catalog中搜寻满足指定条件的product,在这个API消息中,支持多种查询方式,比如名称,比如按照所遵循的行业规范等。
<find_product>
<authInfo>……</authInfo>
<category categoryKey="…" />
<name />
<compliantSpecBag />
<parameterBag>
</find_product>
|
在find_product消息中,支持四种搜索条件:
- category,该元素描述了待搜索category子树的根。表明待执行的搜索的空间是由该元素中的categoryKey所标识的category的所有子元素组成。
- name,这个name元素中描述的字符串是作为名串的最左子串存在的,在搜索中实施的也是最左匹配,比如在这个name元素中描述了"中国"那么"中国汽车","中国计算机"就会被匹配到,而"优质中国汽车"就不会被匹配到。
- compliantSpecBag,该元素中描述了一个业界规范的聚集,依靠这个搜索时指定的聚集,我们就可以将所有不符合这些规范的计算机产品排除在搜索结果集之外。例如该元素中包含了两个规范USB1.1和IEEE1394,那么只有同时支持这两个规范的产品才会被搜索到。
- parameterBag,该元素中描述了一个技术参数的聚集,其使用方式与compliantSpecBag类似,所有不符合所描述的技术参数指定的计算机产品将被排除在搜索结果集之外。
对于compliantSpecBag和parameterBag默认的搜索中的处理行为是逻辑与的方式,我们可以通过参数指定来定义逻辑或的方式。例如:
<compliantSpecBag>
<logicBehavior value="OR" />
<specification specificationKey="Key[USB1.1]" />
<specification specificationKey="Key[IEEE1394]" />
</compliantSpecBag>
|
这个例子表示需要搜索的计算机产品要么兼容USB1.1,要么兼容IEEE1394接口,那么不支持这两种规范中任一规范的计算机产品将被排除在搜索结果集之外。
find_product消息调用的返回是一个或多个被匹配到的product信息,但改信息列表是一个概要信息的列表。下面是一个返回消息的例子:
<result>
<product productKey="p01" parentCategoryKey="a01" />
<name>……</name>
<description>……</description>
</product>
<product productKey="p02" parentCategoryKey="a01" />
<name>……</name>
<description>……</description>
</product>
</result>
|
在分析了上述三个API消息之后,我们不难理解save_product、delete_product和find_category和前面三个消息基本类似,且形式更为简化,因此就不在详细说明,浪费篇幅了。
而对于其余三个消息:get_categoryDetail,get_productDetail和get_categoryInfo,一来这三个消息相对简单,传入键值返回实体信息,二来经过前面的演示,相信大家应该有了一个具体的认识,因此在这里就不花篇幅定义具体消息了。
Member Service
对于Member Service而言,提供两个API消息:
get_authToken
用于向Member Service请求一个认证令牌。在调用其他所有API 时都需要使用认证令牌。此函数在功能上等价于那些完成登录请求的程序。
<get_authToken generic="2.0" xmlns="urn:uddi-org:api_v2"
userID="someLoginName"
password="somePassword" />
|
userID参数必须出现,表示在线服务所授权的个体用户。Member Service提供对用户所提供的用户ID和密码进行有效性检查的方法。password参数必须出现,它表示了用户ID所对应的密码。
discard_authToken
用于通知Member Service,先前提供的认证令牌不再有效。当其他Web服务在Member Service接受到本消息之后,仍然收到这一认证令牌的使用,那么其他Web服务应当判断其为非法。
<discard_authToken generic="2.0" xmlns="urn:uddi-org:api_v2" >
<authInfo/>
</discard_authToken>
|
authInfo这个参数是必需的,它是一个包含了认证令牌的元素。认证令牌可以使用 get_authToken API调用来获得。
Feedback Service
- save_feedback: 保存feedback,在这个API调用中,包含了更新和新建的操作,同时category的迁移也可以通过这个API来完成。另外,使用这个API还能完成删除的操作(之所以这样设计是因为考虑到删除是万不得已才会发生的操作),删除操作通过仅传入feedbackKey和authInfo来完成操作。
- find_feedback: 在catalog中定位寻找feedback,比如名称,比如categoryKey等。
- get_feedbackDetail: 获取一个category下同层所有feedback的详细信息。
- get_feedbackInfo: 获取一个category下整个子树中所有feedback的详细信息。
Order Service
- request_order: 发出订单请求,在这个API中包含了申请新订单和取消订单的两个操作。当传入的orderKey为空并包含其他细节内容时,即为申请新订单操作。如果传入的orderKey为已有的order的键值,同时不包含order的其他细节内容,那么即认为其是取消订单的操作。该消息的返回分别可以指明对于订单请求的接受或拒绝指示。
- get_orderDetail: 获取订单的详细情况,用于在事后参阅。
- find_order: 搜索按照输入参数指明的条件的相关订单。
描述与注册: 发布Web服务
在本文中,详细描述和介绍了Web服务的API是如何设计和定义的,其中介绍了一些基本的设计和应用的模式。在本系列之后的文章中,我将以使用WSDL描述Web服务,以及使用UDDI注册Web服务来结束这个系列。
参考资料
- Web Service 技术/评论网站
- 解决B2B电子商务应用交互和集成的InterOP Stack系列技术标准规范
- UDDI执行白皮书, UDDI-China.org, UDDI.org
- UDDI技术白皮书, UDDI-China.org, UDDI.org
- UDDI程序员API规范, UDDI-China.org, UDDI.org
- UDDI数据结构参考, UDDI-China.org, UDDI.org
- Web Service Description Language (WSDL) 1.0, IBM, 25 Sep 2000
- SOAP: Simple Object Access Protocol Specification 1.1, IBM, Microsoft, DevelopMentor, 2000
- Extensible Markup Language (XML) 1.0 (Second Edition), W3C, 6 Oct 2000
作者简介
柴晓路: 上海得易电子商务技术有限公司(DealEasy)首席系统架构师、XML技术顾问。UDDI-China.org蓝色火焰工作室(Blue Blaze Studio)成员。UDDI Advisor Group成员,WSUI Working Group成员。2000年获复旦大学计算机科学硕士学位,曾在国际计算机科学学术会议(ICSC)、亚太区XML技术研讨会(XML Asia/Pacific'99)、中国XML技术研讨会(北京)、计算机科学期刊等各类国际、国内重要会议与期刊上发表论文多篇。专长于基于XML的系统集成和数据交换的技术研究,同时对数据库、面向对象技术及CSCW等技术比较擅长。
|