CherryPy 和 RESTful Web API
在CherryPy中创建一个RESTful网络API的最佳方法是什么呢?我这几天一直在找,但似乎没有什么特别好的方案。对于Django来说,有很多工具可以做到这一点,但CherryPy似乎没有,或者我还没发现。
后续补充:我应该如何使用CherryPy将像/getOrders?account=X&type=Y这样的请求转换成/orders/account/type这样的形式呢?
5 个回答
你想把/getOrders?account=X&type=Y这样的链接变成/orders/account/type,使用Cherrypy来实现。
我建议你参考一下这个链接,正如@Tomasz Blachowicz提到的,稍微做一些修改。
记住,你可以用下面的方式来处理类似/orders/account/type的链接:
@cherrypy.expose
def order(account=None, type=None):
print account, type
class Root(object):
pass
root = Root()
root.orders = orders
cherrypy.quickstart(root, '/')
所以,如果你看一下这个链接中的例子,你可以修改它来处理这种类型的URL。
class Orders(object):
exposed = True
def __init__(self):
pass
def GET(self, account=None, type=None):
#return the order list for this account type
return getOrders(account, type)
def PUT(self, account=None, type=None, orders=None):
#Set the orders associated with account or something
setOrders(account, type, orders)
class Root(object):
pass
root = Root()
root.orders = Orders()
conf = {
'global': {
'server.socket_host': '0.0.0.0',
'server.socket_port': 8000,
},
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
},
}
cherrypy.quickstart(root, '/', conf)
至于为什么你想用PUT方法来设置订单,我不太清楚,但这确实给了你另一个关于如何使用PUT方法的例子。你只需要把请求中使用的方法换成PUT,它就会调用Orders的PUT()方法,而对Orders使用常规的GET请求时,它会调用GET()方法。因为没有定义POST()方法,所以这个例子不能用POST。如果你尝试使用POST或DELETE,你会收到“405 方法不允许”的错误。
我喜欢这种方法,因为它很容易理解发生了什么,我相信这能解答你的问题。
因为HTTP定义了这些调用方法,所以在使用CherryPy实现REST时,最直接的方式是使用MethodDispatcher,而不是默认的调度器。
更多信息可以在CherryPy的文档中找到: http://cherrypy.readthedocs.io/en/latest/tutorials.html#tutorial-7-give-us-a-rest
这里还有关于如何使用CherryPy工具发送和接收JSON的详细说明: http://tools.cherrypy.org/wiki/JSON
我不知道这是不是“最佳”方法,但这是我做的方式:
import cherrypy
class RESTResource(object):
"""
Base class for providing a RESTful interface to a resource.
To use this class, simply derive a class from it and implement the methods
you want to support. The list of possible methods are:
handle_GET
handle_PUT
handle_POST
handle_DELETE
"""
@cherrypy.expose
def default(self, *vpath, **params):
method = getattr(self, "handle_" + cherrypy.request.method, None)
if not method:
methods = [x.replace("handle_", "")
for x in dir(self) if x.startswith("handle_")]
cherrypy.response.headers["Allow"] = ",".join(methods)
raise cherrypy.HTTPError(405, "Method not implemented.")
return method(*vpath, **params);
class FooResource(RESTResource):
def handle_GET(self, *vpath, **params):
retval = "Path Elements:<br/>" + '<br/>'.join(vpath)
query = ['%s=>%s' % (k,v) for k,v in params.items()]
retval += "<br/>Query String Elements:<br/>" + \
'<br/>'.join(query)
return retval
class Root(object):
foo = FooResource()
@cherrypy.expose
def index(self):
return "REST example."
cherrypy.quickstart(Root())
你只需要从 RESTResource
类继承,然后处理你想要的 RESTful 请求方式(比如 GET、PUT、POST、DELETE),每种请求方式用一个以 handle_
开头的方法来处理。如果你没有处理某个请求方式(比如 POST),那么基础类会自动给你抛出一个 405 Method Not Implemented
的错误。
路径中的项目会通过 vpaths
传递,而任何查询字符串则通过 params
传递。根据上面的示例代码,如果你请求 /foo/bar?woo=hoo
,那么 vpath[0]
就会是 bar
,而 params
的内容会是 {'woo': 'hoo'}
。