RESTful客户端库:RestClient

WebService

话说我刚知道这词的时候还是十二年前…大约2001年,微软的.net刚出来的时候,这货就热了,只不过当年这货的标配通讯协议是SOAP。当年我觉得这货还是很方便的,但是在尝鲜过后,我根本没有兴趣将它用于实际的应用…它实在是太笨重了。

这种笨重包括几个方面:首先SOAP本身的数据结构就很啰嗦,加上XML就更啰嗦了。其次,各种实现技术在高层逻辑上的定义各有一套,实际上并不那么通用。最主要的是要用这货,需要带上太多的开发库什么的,而且用起来实在也没有传说中的那么方便。

说实话,这十二年来,我基本上就没见过像样的应用——听说过一些,也很少,评价普遍也不是很高。在web领域,它甚至未必有xml-rpc常见。

随着RESTful和JSON的流行,新的WebService模型已经成为了事实标准,那就是以标准HTTP请求构建RESTful的API结构,以JSON定义交换协议的数据结构,组成了新一代的轻量级WebService模型。

就 目前来说,提供RESTful API已经成了很多网站的标配…即使你不提供开放平台服务,也要考虑到移动应用啊,没有比这更好的实现方案了——技术足够 成熟(大网站都在用)、节约资源(大多数时候,这意味着性能更好)、简单轻量(需要学习的东西不多,依赖的东西也不多)。

更详细的理由可以参考一下CSDN的CTO范凯的这篇文章《Ruby社区应该去Rails化了》。

这其中最著名的应该是Facebook的开放平台,而应用最广泛的则是Twitter的API接口。国内的山寨版本就是像人人网、微博网之类的。

因 为个人使用需要,我对Twitter的API有过一段时间研究,不过坦白说,Twitter的这套API定义得相当不够RESTful,要学习如何定义 API,还是强烈建议学习foursquare的API v2(当前版本),这才是规范的RESTful实现…不过它们的API经常不定期微调,所以需要一个v参数,这点略不规范。

RESTful客户端

回到主题上,说了这么多关于RESTful WebService的话题,本文主要还是要介绍RESTful客户端的技术。

关于客户端对RESTful WebService的调用,有很多方法,理论上只要是支持标准HTTP请求的方法都可以用。比如我前两年在介绍OAuth 1.0a/OAuth 2.0的时候用的例子便是用PHP的curl库实现的。至于python就更方便了,除了自带的urllib之类,还有httplib什么的,但是最方便的还要算是requests。

但是对我来说,这还不够方便。

用过SOAP的人都知道,SOAP有个好东西叫做WSDL,通过导入这个东西,可以生成一个wrapper,使得远程调用的使用像本地方法调用一样简单,对于静态语言来说,还可以提供语法检查。

但是RESTful WebService就没有这种东西了,只有一份给人看的文档,还需要人工自己转成代码——当然通常服务端也会有提供参考实现的库,但总是不方便——因为每个服务商都有自己一套,现在API这么多,实现风格又各异,学起来太麻烦,还容易搞错。

要是再加上各种Authentication/Authorization,麻烦的事情就更多了。

于是我想到利用动态语言的动态性,对这些请求进行动态的wrapping,做了这个通用库。

基本的RESTful请求

在谈论这个库的使用之前,先说一下基本的RESTful请求结构:

一般来说请求由这几个主要部分组成:HTTP请求方法(GET,POST,PUT,DELETE...),URI,参数。

除此之外,还可能用到的内容有:HTTP请求头,HTTP响应代码。

一个常见的例子类似这样:

GET http://api.yourserver.com/v1/objects/function?id=xxxx

或者:

GET http://api.yourserver.com/v1/objects/xxxx/function

其中的xxxx就是id参数

对于支持多种数据格式的WebService(如早期的Twitter和现在的饭否,都支持除JSON以外的XML和RSS两种格式),在URI上还会有格式后缀,如:

GET http://api.yourserver.com/v1/objects/xxxx/function.xml

而在如BasicAuth或Header方式的OAuth1.0a/2.0下,还需要操作HTTP请求头。出错的时候还需要处理HTTP响应代码。

这些都是不必要的麻烦。所以我做了这么个库试图解决这些问题。

我的目标是把这类的请求包装起来,通过标准的Python调用来实现。比如上面的请求可以简化为这样的Python代码:

api.object.GET_function(xxxx)

这样就方便多了。

RestClient库

这个库就一个文件,包括两个方面:Auth和APIClient。

其中APIClient是一个wrapper,用于实现动态将python调用转为RESTful请求。Auth部分包括了常用的BasicAuth, OAuth1.0a, OAuth2.0三种认证方式。

对于那么多的API是不是需要对每个API去实现一个api类,对于每个API的那么多功能,是不是需要实现一堆的objects类和无数的function方法呢?那样不就跟服务端提供的库一样了嘛。

答案当然是不需要。

以饭否为例,实现一个饭否API只需要这么几行代码:

class Fanfou(APIClient):
    def __init__(self, client_key, client_secret, callback="", access_token=""):
        APIClient.__init__(self, AuthOAuth1("http://fanfou.com/oauth", client_key, client_secret, callback=callback, access_token=access_token),
                "http://api.fanfou.com", 
                ['search', 'blocks', 'users', 'account', 'saved_searches', 'photos', 'trends', 
                    'followers', 'favorites', 'friendships', 'friends', 'statuses', 'direct_messages'], 
                "json")

关于其中的参数,简单解释一下:

父类APIClient需要五个参数:auth, api_url, object_list, postfix, ssl_verify

其 中auth是一个auth对象,用来指定用哪种认证方式。api_url是指API请求的URL,即所有RESTful请求的URI最前面共同的那一部 分。object_list是可选的,没有这一项的话,可以使用任意名字的object,如果有这个list,则只能使用这里列出的部分,建议提供这个参 数,这样可以不用等到服务端返回404才知道搞错名字。postfix是格式后缀,如服务端不需要加后缀,这个参数可以不用。注意:没有json和空以外 的其它选择,本库不支持XML或RSS格式。ssl_verify用于SSL证书检查,默认为True,但是因为requests似乎不是使用操作系统的 证书体系,而是自己弄了一套,所以有些正常的SSL网站也会报SSL验证错误,另外对一些使用自签名证书的网站(理由你懂的),也需要将这个参数设置为 False才不报错。

这里使用了OAuth1.0a,AuthOAuth1需要四个参数:auth_url, client_key, client_secret, callback, access_token。auth_url是请求认证的调用的根URL,中间二者来自于你的服务端所提供,callback是回调你的客户端时用的 URL。具体参见OAuth 1.0a规范文档或我以前的文章说明。最后一个access_token则是对于预先保存过access_token的情况下,可以直接使用,不用每次重 新登录授权。

使用的方法也很简单,关于OAuth 1.0a的请求部分原理参见我以前的文章,这里不再重复,使用方法参见项目的demoweb.py这个web服务程序例子。

假设已经完成登录,取得了有效的access_token,可以这样调用饭否API:

fan = Fanfou(client_key, client_secret, access_token=access_token)  # 前两个参数来自服务端所提供,最后一个参数来自登录后取得的access_token
user = fan.account.GET_verify_credentials()  # 调用 GET http://api.fanfou.com/account/verify_credentials
# user 对象就是取得的调用结果

本项目已经发布在bitbucket:https://bitbucket.org/raptorz/restclient

(不过因为某些脑子被枪打过的家伙在领导着这个国家的互联网,所以目前在中国大陆境内访问 bitbucket.org 和 github.com 都不太顺畅,丫们真是中国技术创新最大的敌人,真不知道这两个分享源代码的网站哪里戳到丫们的G点了…)

目前我已经提供了饭否、Foursquare和Google(只包含登录功能)等的三个API包装,再增加别的包装也是很容易的事情。

推送到[go4pro.org]