Дружественный URL для веб-сервиса REST с CherryPy
Я делаю RESTful WebService, используя CherryPy 3, но я сталкиваюсь с проблемой : Я хочу иметь возможность отвечать на такие запросы, как : / клиенты/1/продукты / 386 означает, что я хочу весь продукт с ID 386 клиента с ID 1.
поэтому я пытаюсь сделать это с MethodDispatcher CherryPy следующим образом:
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.Получите с правильными параметрами, он перенаправляет меня в UserController.Получаем с параметрами 1, "продукты", 386.
для перенаправления на ProductController.GET мне нужно запросить /customers/products / 386, что неверно, потому что я пропускаю параметр user ID.
Я видел на этой презентации : RESTful веб-приложений с CherryPy что стиль пути, который я хочу использовать, кажется хорошим выбором. Но есть ли простой способ реализовать его с помощью Cherry Py ?
Я слышал о _cp_dispatch метод CherryPy 3, но я не понимаю, что это такое и как его использовать. Заменяет ли он MethodDispatcher ?
2 ответов
CherryPy использует древовидный картограф, который не подходит для сегментов, которые не имеют физической реальности в качестве объекта Python, здесь ваш / 1 / сегмент.
С учетом сказанного, CherryPy предоставляет функциональные возможности для достижения вашей цели.
- Swap для более явного картографа, такого как селектор или маршруты.
- использовать _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, вероятно, будет намного проще в моей книге. Очевидно, что и то и другое можно использовать одновременно.
Спасибо за ваш ответ Сильвен. Вы привели меня к ответу, который я искал. Я использовал 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']))