CherryPy и RESTful web api
Каков наилучший подход к созданию веб-страницы RESTful в CherryPy? Я смотрю вокруг уже несколько дней, и ничего не кажется большим. Для Django кажется, что для этого есть множество инструментов, но не для CherryPy, или я не знаю о них.
Позже отредактируйте: Как использовать Cherrypy для преобразования запроса типа /getOrders? account = X & type = Y в нечто вроде/orders/account/type?
Ответы
Ответ 1
Я не знаю, является ли это "лучшим" способом, но вот как я это делаю:
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
и обрабатываете любые требуемые глаголы RESTful (GET, PUT, POST, DELETE) с использованием метода с тем же именем с префиксом handle_
. Если вы не обрабатываете определенный глагол (например, POST), базовый класс поднимет для вас ошибку 405 Method Not Implemented
.
Элементы пути передаются в vpaths
, и любые строки запроса передаются в params
. Используя приведенный выше пример кода, если вы хотите запросить /foo/bar?woo=hoo
, vpath[0]
будет bar
, а params
будет {'woo': 'hoo'}
.
Ответ 2
Поскольку HTTP определяет эти методы вызова, самый прямой способ реализовать REST с использованием CherryPy - использовать MethodDispatcher вместо диспетчера по умолчанию.
Подробнее можно найти в документах CherryPy:
http://cherrypy.readthedocs.io/en/latest/tutorials.html#tutorial-7-give-us-a-rest
Вот также подробное описание того, как отправлять и получать JSON с помощью инструментов CherryPy:
http://tools.cherrypy.org/wiki/JSON
Ответ 3
Итак, вы хотите преобразовать /getOrders? account = X & type = Y в нечто вроде /orders/account/type с помощью Cherrypy.
Я бы попытался использовать метод http://cherrypy.readthedocs.org/en/latest/tutorial/REST.html, как упоминал @Tomasz Blachowicz, с некоторыми изменениями.
Помните, что вы можете обрабатывать что-то вроде /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, и будет использовать метод PUT() Orders и использовать регулярное GET на Orders, и он будет использовать метод GET(). Поскольку метод POST() не определен, POST не может использоваться с этим примером. Если вы попробуете POST или DELETE, вы получите "405 Method Not Allowed".
Мне нравится этот подход, потому что легко понять, что происходит, и, я считаю, он отвечает на ваш вопрос.
Ответ 4
Я предполагаю, что вы пробовали частичные совпадения, о которых говорилось в учебнике. Я нахожу, что, хотя это и не очень хорошо, он выполняет большую часть времени.
Помимо этого, хотя я и не пробовал, Cherrypy, по-видимому, поддерживает Routes (см. http://www.cherrypy.org/wiki/PageHandlers), который предоставляет вам все варианты RESTful.
Ответ 5
Чтобы ответить на второй вопрос, вы хотите определить и выставить метод по умолчанию:
class getOrders(Object):
def default(account, type):
...
default.exposed = True
используя этот метод, getOrders/x/y будет отображаться в default(account='x', type='y')
. Как и кто-то другой, это не здорово, но он выполняет свою работу.
Что касается приложений RESTful, я уверен, что обработчик страницы по умолчанию будет работать для такого приложения.