Friendly URL for a REST WebService with CherryPy

前端 未结 2 2002
终归单人心
终归单人心 2021-01-31 21:05

I\'m making a RESTful WebService using CherryPy 3 but I encounter a problem : I want to be able to answer requests like : /customers/1/products/386 meaning I wa

相关标签:
2条回答
  • 2021-01-31 21:36

    CherryPy uses a tree-based mapper which does not accommodate well with segments that have no physical reality as a Python object, here your /1/ segment.

    With that said, CherryPy does provide functionalities to reach your goal.

    • Swap to a more explicit mapper such as selector or routes.
    • Use _cp_dispatch
    • Use cherrypy.popargs

    Let's focus on the last two.

    _cp_dispatch is a special method you declare in any of your controller to massage the remaining segments before CherryPy gets to process them. This offers you the capacity to remove, add or otherwise handle any segment you wish and, even, entirely change the remaining parts.

    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 is more straightforward as it gives a name to any segment that CherryPy wouldn't be able to interpret otherwise. This makes the matching of segments with page handler signatures easier and help CherryPy understand the structure of your 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())
    

    In both cases go to http://whatevertomakesohappy.com:8080/nirvana/ and then http://whatevertomakesohappy.com:8080/nirvana/albums/nevermind/

    Both are powerful but which one you want to use is up to you. For simple URLs, popargs is likely to be much easier in my book. Obviously both can be used concurrently.

    0 讨论(0)
  • 2021-01-31 21:38

    Thanks for your answer Sylvain. You've led me to the answer I was looking for. I used the RouteDispatcher like this :

        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']))
    
    0 讨论(0)
提交回复
热议问题