CherryPy и RESTful веб-API - PullRequest
       23

CherryPy и RESTful веб-API

13 голосов
/ 26 апреля 2010

Каков наилучший подход к созданию веб-API RESTful в CherryPy? Я искал вокруг в течение нескольких дней, и ничего не кажется отличным. Для Django кажется, что для этого есть много инструментов, но не для CherryPy, или я не знаю о них.

Позднее редактирование: Как использовать Cherrypy для преобразования запроса, подобного / getOrders? Account = X & type = Y, во что-то вроде / orders / account / type?

Ответы [ 5 ]

11 голосов
/ 14 мая 2010

Я не знаю, является ли это «лучшим» способом, но вот как я это делаю:

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'}.

7 голосов
/ 02 февраля 2012

Поскольку HTTP определяет эти методы вызова, наиболее прямой способ реализации REST с использованием CherryPy - это использование MethodDispatcher вместо диспетчера по умолчанию.

Больше информации можно найти в CherryPy документах: http://cherrypy.readthedocs.io/en/latest/tutorials.html#tutorial-7-give-us-a-rest

Вот также подробное описание того, как отправлять и получать JSON с помощью CherryPy Tools: http://tools.cherrypy.org/wiki/JSON

2 голосов
/ 11 марта 2012

То есть вы хотите преобразовать / 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».

Мне нравится этот подход, потому что легко увидеть, что происходит, и, я думаю, он отвечает на ваш вопрос.

1 голос
/ 21 мая 2010

Чтобы ответить на второй вопрос, вы хотите определить и выставить метод по умолчанию:

class getOrders(Object):
    def default(account, type):
        ...

    default.exposed = True

используя этот метод, getOrders / x / y будет отображаться в default(account='x', type='y'). Как сказал кто-то еще, это не здорово, но оно выполняет свою работу.

Что касается приложений RESTful, я почти уверен, что для такого приложения будет работать обработчик страниц по умолчанию.

1 голос
/ 03 мая 2010

Полагаю, вы пробовали частичные совпадения, о которых говорилось в руководстве. Я считаю, что, хотя это и не так здорово, большую часть времени работа выполняется.

Помимо этого, хотя я еще не пробовал, Cherrypy, по-видимому, поддерживает Маршруты (см. http://www.cherrypy.org/wiki/PageHandlers),, который предоставляет все виды параметров RESTful.

...