13

在 CherryPy 中创建 RESTful Web api 的最佳方法是什么?我已经四处寻找了几天,似乎没有什么大不了的。对于 Django 来说,似乎有很多工具可以做到这一点,但对于 CherryPy 来说不是,或者我不知道它们。

稍后编辑:我应该如何使用 Cherrypy 将 /getOrders?account=X&type=Y 之类的请求转换为 /orders/account/type 之类的请求?

4

5 回答 5

11

我不知道这是否是“最好”的方式,但我是这样做的:

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类派生并使用前缀为handle_. 如果您不处理特定动词(例如 POST),则基类将为405 Method Not Implemented您引发错误。

传入路径项,并传入vpaths任何查询字符串params。使用上面的示例代码,如果您要请求/foo/bar?woo=hoovpath[0]将是bar,并且params将是{'woo': 'hoo'}

于 2010-05-14T02:18:35.417 回答
7

因为 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

于 2012-02-02T14:26:43.503 回答
2

因此,您想使用 Cherrypy 将 /getOrders?account=X&type=Y 转换为 /orders/account/type 之类的东西。

我会尝试@Tomasz Blachowicz 提到的http://cherrypy.readthedocs.org/en/latest/tutorial/REST.html中使用的方法,并进行一些修改。

请记住,您可以处理 /order/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, '/')

因此,如果您采用http://cherrypy.readthedocs.org/en/latest/tutorial/REST.html中给出的示例,您可以对其进行修改以处理该类型的 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 Method Not Allowed”。

我喜欢这种方法,因为它很容易看到正在发生的事情,而且我相信它回答了你的问题。

于 2012-03-11T09:04:52.147 回答
1

要回答您的第二个问题,您需要定义并公开一个默认方法:

class getOrders(Object):
    def default(account, type):
        ...

    default.exposed = True

使用此方法,getOrders/x/y 将映射到default(account='x', type='y'). 就像其他人说的那样,它不是很好,但它可以完成工作。

就 RESTful 应用程序而言,我很确定默认页面处理程序适用于这样的应用程序。

于 2010-05-20T21:29:44.263 回答
1

我假设您已经尝试过教程中提到的部分匹配。我发现虽然不是很好,但它确实可以在大多数情况下完成工作。

除此之外,虽然我没有尝试过,但 Cherrypy 显然支持 Routes(参见http://www.cherrypy.org/wiki/PageHandlers),它为您提供了各种 RESTful 选项。

于 2010-05-03T07:47:26.943 回答