CherryPy and RESTful web api
Solution 1
I don't know if it's the "best" way, but here's how I do it:
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())
You simply derive from the RESTResource
class and handle whichever RESTful verbs you desire (GET, PUT, POST, DELETE) with a method of the same name prefixed with handle_
. If you do not handle a particular verb (such as POST) the base class will raise a 405 Method Not Implemented
error for you.
The path items are passed in vpaths
and any query strings are passed in in params
. Using the above sample code, if you were to request /foo/bar?woo=hoo
, vpath[0]
would be bar
, and params
would be {'woo': 'hoo'}
.
Solution 2
Because HTTP defines these invocation methods, the most direct way to implement REST using CherryPy is to utilize the MethodDispatcher instead of the default dispatcher.
More can be found in CherryPy docs: http://cherrypy.readthedocs.io/en/latest/tutorials.html#tutorial-7-give-us-a-rest
Here is also detailed description on how to send and receive JSON using CherryPy Tools: http://tools.cherrypy.org/wiki/JSON
Solution 3
So you want to transform /getOrders?account=X&type=Y into something like /orders/account/type using Cherrypy.
I would try the approach used in http://cherrypy.readthedocs.org/en/latest/tutorial/REST.html as mentioned by @Tomasz Blachowicz, with some modifications.
Remember that you can handle something like /order/account/type with
@cherrypy.expose
def order(account=None, type=None):
print account, type
class Root(object):
pass
root = Root()
root.orders = orders
cherrypy.quickstart(root, '/')
So if you take the example given in http://cherrypy.readthedocs.org/en/latest/tutorial/REST.html, you can modify it to handle that type of 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)
Why you would want to set orders using that put method I don't know, but it does give an another example of how to do PUT methods. All you have to do is replace the method used by a request with PUT and it will use the PUT() method of Orders and use a regular GET on Orders and it will use the GET() method. Because a POST() method is not defined, POST can't be used with this example. If you try POST or DELETE you will get "405 Method Not Allowed".
I like this approach because it is easy to see what is going on and, I believe, it answers your question.
Solution 4
To answer your second question, you want to define and expose a default method:
class getOrders(Object):
def default(account, type):
...
default.exposed = True
using this method, getOrders/x/y would map to default(account='x', type='y')
. Like someone else said, it's not great, but it gets the job done.
As far as RESTful applications goes, I'm pretty sure the default page handler will work for such an application.
Solution 5
I assume you've tried partial matches as talked about in the tutorial. I find that while not great, it does get the job done most of the time.
Beyond that, though I haven't tried it, Cherrypy apparently supports Routes (see http://www.cherrypy.org/wiki/PageHandlers), which gives you all kinds of RESTful options.
Related videos on Youtube
hyperboreean
Updated on August 18, 2021Comments
-
hyperboreean over 2 years
What's the best approach of creating a RESTful web api in CherryPy? I've been looking around for a few days now and nothing seems great. For Django it seems that are lots of tools to do this, but not for CherryPy or I am not aware of them.
Later edit: How should I use Cherrypy to transform a request like /getOrders?account=X&type=Y into something like /orders/account/type ?
-
Sebastian Wagner over 6 yearsLast link is gone now.