使用CherryPy的REST WebService的友好URL

Yoh*_*n D 15 python rest web-services 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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

我听说过CherryPy 3的_cp_dispatch方法,但我没有得到它究竟是什么以及如何使用它.它是否取代了MethodDispatcher?

Syl*_*rch 22

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

话虽如此,CherryPy确实提供了实现目标的功能.

  • 切换到更明确的映射器,例如选择器路由.
  • 使用_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())
Run Code Online (Sandbox Code Playgroud)

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())
Run Code Online (Sandbox Code Playgroud)

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

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


Yoh*_*n D 5

谢谢你的回答西尔万.你引导我找到了我想要的答案.我像这样使用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']))
Run Code Online (Sandbox Code Playgroud)