使用CherryPy的REST WebService的友好URL

时间:2013-04-03 12:09:31

标签: python web-services rest cherrypy

我正在使用CherryPy 3制作RESTful WebService但我遇到了一个问题: 我希望能够回答以下请求: / customers / 1 / products / 386 表示我想要ID为1的客户ID为386的所有产品。

所以我尝试使用CherryPy的MethodDispatcher这样做:

class UserController(object):
    exposed = True

    def __init__(self):
        self.product = ProductController()

    @log_io
    def GET(self, *args):
        return "GET Users :" + str(args)


class ProductController(object):
    exposed = True
    @log_io
    def GET(self, *args):
        return "GET Product :" + str(args)

但是当我请求/ customers / 1 / products / 386时,不是使用正确的参数将我重定向到ProductController.GET,而是使用参数1,“products”,386将我重定向到UserController.GET。

要重定向到ProductController.GET我必须查询/ customers / products / 386这是不正确的,因为我错过了用户ID参数。

我在这个演示文稿中看到:RESTful Web Applications with CherryPy我想要使用的路径样式似乎是一个不错的选择。但有没有一种简单的方法来实现Cherry Py?

我听说过CherryPy 3的_cp_dispatch方法,但我不知道它到底是什么以及如何使用它。它是否取代了MethodDispatcher?

2 个答案:

答案 0 :(得分:22)

CherryPy使用基于树的映射器,它不能很好地适应没有物理现实的段作为Python对象,这里是你的/ 1 /段。

据说,CherryPy确实提供了实现目标的功能。

  • 切换到更明确的映射器,例如selectorroutes
  • 使用_cp_dispatch
  • 使用cherrypy.popargs

让我们关注最后两个。

_cp_dispatch是一种特殊方法,您可以在任何控制器中声明,以便在CherryPy处理它们之前按下剩余的段。这使您能够移除,添加或以其他方式处理您希望的任何细分,甚至完全更改其余部分。

import cherrypy

class Band(object):
    def __init__(self):
        self.albums = Album()

    def _cp_dispatch(self, vpath):
        if len(vpath) == 1:
            cherrypy.request.params['name'] = vpath.pop()
            return self

        if len(vpath) == 3:
            cherrypy.request.params['artist'] = vpath.pop(0)  # /band name/
            vpath.pop(0) # /albums/
            cherrypy.request.params['title'] = vpath.pop(0) # /album title/
            return self.albums

        return vpath

    @cherrypy.expose
    def index(self, name):
        return 'About %s...' % name

class Album(object):
    @cherrypy.expose
    def index(self, artist, title):
        return 'About %s by %s...' % (title, artist)

if __name__ == '__main__':
    cherrypy.quickstart(Band())

cherrypy.popargs更直接,因为它为CherryPy无法解释的任何段命名。这使得段与页面处理程序签名的匹配更容易,并帮助CherryPy理解URL的结构。

import cherrypy

@cherrypy.popargs('name')
class Band(object):
    def __init__(self):
        self.albums = Album()

    @cherrypy.expose
    def index(self, name):
        return 'About %s...' % name

@cherrypy.popargs('title')
class Album(object):
    @cherrypy.expose
    def index(self, name, title):
        return 'About %s by %s...' % (title, name)

if __name__ == '__main__':
    cherrypy.quickstart(Band())

在这两种情况下,请转到http://whatevertomakesohappy.com:8080/nirvana/,然后转到http://whatevertomakesohappy.com:8080/nirvana/albums/nevermind/

两者都很强大,但您想要使用哪一个取决于您。对于简单的URL,popargs在我的书中可能会容易得多。显然两者都可以同时使用。

答案 1 :(得分:5)

感谢您的回答Sylvain。你引导我找到了我想要的答案。 我像这样使用RouteDispatcher:

    self.connect("cust_products", "/customers/{cust_id}/products/",
                 controller=CustomerController(),
                 action='index',
                 conditions=dict(method=['GET']))

    self.connect("cust_products", "/customers/{cust_id}/products/{id}",
                 controller=CustomerController(),
                 action='show',
                 conditions=dict(method=['GET']))

    self.connect("cust_products", "/customers/{cust_id}/products/",
                 controller=CustomerController(),
                 action='create',
                 conditions=dict(method=['POST']))

    self.connect("cust_products", "/customers/{cust_id}/products/{id}",
                 controller=CustomerController(),
                 action='update',
                 conditions=dict(method=['PUT']))


    self.connect("cust_products", "/customers/{cust_id}/products/{id}",
                 controller=CustomerController(),
                 action='delete',
                 conditions=dict(method=['DELETE']))
相关问题