321
votes

Is there a list somewhere of recommendations of different Python-based REST frameworks for use on the serverside to write your own RESTful APIs? Preferably with pros and cons.

Please feel free to add recommendations here. :)

1

16 Answers 16

192
votes

Something to be careful about when designing a RESTful API is the conflation of GET and POST, as if they were the same thing. It's easy to make this mistake with Django's function-based views and CherryPy's default dispatcher, although both frameworks now provide a way around this problem (class-based views and MethodDispatcher, respectively).

HTTP-verbs are very important in REST, and unless you're very careful about this, you'll end up falling into a REST anti-pattern.

Some frameworks that get it right are web.py, Flask and Bottle. When combined with the mimerender library (full disclosure: I wrote it), they allow you to write nice RESTful webservices:

import web
import json
from mimerender import mimerender

render_xml = lambda message: '<message>%s</message>'%message
render_json = lambda **args: json.dumps(args)
render_html = lambda message: '<html><body>%s</body></html>'%message
render_txt = lambda message: message

urls = (
    '/(.*)', 'greet'
)
app = web.application(urls, globals())

class greet:
    @mimerender(
        default = 'html',
        html = render_html,
        xml  = render_xml,
        json = render_json,
        txt  = render_txt
    )
    def GET(self, name):
        if not name: 
            name = 'world'
        return {'message': 'Hello, ' + name + '!'}

if __name__ == "__main__":
    app.run()

The service's logic is implemented only once, and the correct representation selection (Accept header) + dispatch to the proper render function (or template) is done in a tidy, transparent way.

$ curl localhost:8080/x
<html><body>Hello, x!</body></html>

$ curl -H "Accept: application/html" localhost:8080/x
<html><body>Hello, x!</body></html>

$ curl -H "Accept: application/xml" localhost:8080/x
<message>Hello, x!</message>

$ curl -H "Accept: application/json" localhost:8080/x
{'message':'Hello, x!'}

$ curl -H "Accept: text/plain" localhost:8080/x
Hello, x!

Update (April 2012): added information about Django's class-based views, CherryPy's MethodDispatcher and Flask and Bottle frameworks. Neither existed back when the question was asked.

9
  • 12
    This is incorrect, Django has full support for recognizing POST vs GET and limiting views to only certain methods.
    – aehlke
    Jul 23, 2009 at 14:18
  • 20
    I meant that, by default, Django treats POST and GET as if they were the same thing, which is very inconvenient when you are doing RESTful services as it forces you to do: if request.method == 'GET': do_something() elif request.method == 'POST': do_something_else() web.py doesn't have that problem Aug 4, 2009 at 11:48
  • 19
    @Wahnfrieden: If there is native support in Django for handling different HTTP verbs separately (by "native" I mean not needing "if request.method==X"), could you please point me to some documentation? Aug 4, 2009 at 15:34
  • 3
    The conflation of POST and GET does not apply to Django's Class Based Views (added in 1.3), but I believe is valid for the earlier releases.
    – ncoghlan
    Oct 11, 2011 at 8:21
  • 1
    Answer is incorrect about CherryPy. From Docs: "REST (Representational State Transfer) is an architectural style that is well-suited to implementation in CherryPy." - docs.cherrypy.org/dev/progguide/REST.html
    – Derek Litz
    Jan 26, 2012 at 4:41
70
votes

Surprised no one mentioned flask.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()
10
  • 7
    Flask wasn't out there when the question was asked... Apr 11, 2012 at 17:43
  • 2
    Flask doesn't work with Python 3.x
    – Alex Bitek
    Feb 12, 2013 at 15:57
  • 3
    Flask.dev now supports Python 3 Jun 12, 2013 at 0:48
  • 2
    Flask supports Python 3.3 or higher.
    – mb21
    Aug 27, 2013 at 19:20
  • 3
    noob here, how this is a RESTful?
    – avi
    Dec 5, 2013 at 6:03
23
votes

We're using Django for RESTful web services.

Note that -- out of the box -- Django did not have fine-grained enough authentication for our needs. We used the Django-REST interface, which helped a lot. [We've since rolled our own because we'd made so many extensions that it had become a maintenance nightmare.]

We have two kinds of URL's: "html" URL's which implement the human-oriented HTML pages, and "json" URL's which implement the web-services oriented processing. Our view functions often look like this.

def someUsefulThing( request, object_id ):
    # do some processing
    return { a dictionary with results }

def htmlView( request, object_id ):
    d = someUsefulThing( request, object_id )
    render_to_response( 'template.html', d, ... )

def jsonView( request, object_id ):
    d = someUsefulThing( request, object_id )
    data = serializers.serialize( 'json', d['object'], fields=EXPOSED_FIELDS )
    response = HttpResponse( data, status=200, content_type='application/json' )
    response['Location']= reverse( 'some.path.to.this.view', kwargs={...} )
    return response

The point being that the useful functionality is factored out of the two presentations. The JSON presentation is usually just one object that was requested. The HTML presentation often includes all kinds of navigation aids and other contextual clues that help people be productive.

The jsonView functions are all very similar, which can be a bit annoying. But it's Python, so make them part of a callable class or write decorators if it helps.

16
  • 2
    Awful repetition of d = someUsefulThing... Even Django guys suggest DRY.
    – temoto
    Jul 9, 2010 at 11:32
  • 5
    @temoto: If y = someUsefulThing(...) is an "Awful repetition", then all references to all functions and methods is "awful". I fail to understand how to avoid referencing a function more than once.
    – S.Lott
    Jul 12, 2010 at 2:07
  • 5
    @temoto: "When you need to change arguments passed to someUsefulThing, there's a chance that one forgets to do so in all calls"? What? How is that "awful"? That's a trivial consequence of referencing a function more than once. I'm failing to understand what you're talking about and how function reference is "awful" since it's inescapable.
    – S.Lott
    Jul 12, 2010 at 9:58
  • 4
    See the accepted answer. The result expression {'message': 'Hello, ' + name + '!'} is written once for all presentations.
    – temoto
    Jul 12, 2010 at 11:54
  • 3
    Your htmlView and jsonView functions serve different representations for same data, right? So someUsefulThing(request, object_id) is a data retrieval expression. Now you have two copies of same expression in different points in your program. In the accepted answer, the data expression is written once. Replace your someUsefulThing call with a long string, like paginate(request, Post.objects.filter(deleted=False, owner=request.user).order_by('comment_count')) and look at the code. I hope it will illustrate my point.
    – temoto
    Jul 13, 2010 at 18:32
11
votes

See Python Web Frameworks wiki.

You probably do not need the full stack frameworks, but the remaining list is still quite long.

8
votes

I really like CherryPy. Here's an example of a restful web service:

import cherrypy
from cherrypy import expose

class Converter:
    @expose
    def index(self):
        return "Hello World!"

    @expose
    def fahr_to_celc(self, degrees):
        temp = (float(degrees) - 32) * 5 / 9
        return "%.01f" % temp

    @expose
    def celc_to_fahr(self, degrees):
        temp = float(degrees) * 9 / 5 + 32
        return "%.01f" % temp

cherrypy.quickstart(Converter())

This emphasizes what I really like about CherryPy; this is a completely working example that's very understandable even to someone who doesn't know the framework. If you run this code, then you can immediately see the results in your web browser; e.g. visiting http://localhost:8080/celc_to_fahr?degrees=50 will display 122.0 in your web browser.

4
  • 35
    That's a nice example, but there's nothing RESTful about it.
    – aehlke
    Jul 23, 2009 at 14:15
  • 3
    @Wahnfrieden: Could you help the rest of us out by clarifying why you do not think the above is RESTful? From my point of view, it looks like a classic example of REST and doesn't appear to break any of the rules or constraints of a RESTful system.
    – lilbyrdie
    Aug 11, 2009 at 0:34
  • 42
    In simple terms, what the CherryPy example above is doing is exposing methods as "HTTP callable" remote procedures. That's RPC. It's entirely "verb" oriented. RESTful architectures focus on the resources managed by a server and then offer a very limited set of operations on those resources: specifically, POST (create), GET (read), PUT (update) and DELETE (delete). The manipulation of these resources, in particular changing their state via PUT, is the key pathway whereby "stuff happens".
    – verveguy
    Sep 11, 2009 at 14:26
  • 2
    You can write more RESTfull APIs using CherryPy docs.cherrypy.org/stable/progguide/REST.html
    – tabdulradi
    Jan 1, 2013 at 13:16
8
votes

Take a look at

0
8
votes

I don't see any reason to use Django just to expose a REST api, there are lighter and more flexible solutions. Django carries a lot of other things to the table, that are not always needed. For sure not needed if you only want to expose some code as a REST service.

My personal experience, fwiw, is that once you have a one-size-fits-all framework, you'll start to use its ORM, its plugins, etc. just because it's easy, and in no time you end up having a dependency that is very hard to get rid of.

Choosing a web framework is a tough decision, and I would avoid picking a full stack solution just to expose a REST api.

Now, if you really need/want to use Django, then Piston is a nice REST framework for django apps.

That being said, CherryPy looks really nice too, but seems more RPC than REST.

Looking at the samples (I never used it), probably web.py is the best and cleanest if you only need REST.

6
votes

Here is a discussion in CherryPy docs on REST: http://docs.cherrypy.org/dev/progguide/REST.html

In particular it mentions a built in CherryPy dispatcher called MethodDispatcher, which invokes methods based on their HTTP-verb identifiers (GET, POST, etc...).

6
votes

In 2010, the Pylons and repoze.bfg communities "joined forces" to create Pyramid, a web framework based most heavily on repoze.bfg. It retains the philosophies of its parent frameworks, and can be used for RESTful services. It's worth a look.

1
  • With Pyramid you can make use of Cornice, which provides useful helpers for building and documenting REST web services.
    – Calvin
    Dec 27, 2013 at 14:04
5
votes

Piston is very flexible framework for wirting RESTful APIs for Django applications.

5
votes

Seems all kinds of python web frameworks can implement RESTful interfaces now.

For Django, besides tastypie and piston, django-rest-framework is a promising one worth to mention. I've already migrated one of my project on it smoothly.

Django REST framework is a lightweight REST framework for Django, that aims to make it easy to build well-connected, self-describing RESTful Web APIs.

Quick example:

from django.conf.urls.defaults import patterns, url
from djangorestframework.resources import ModelResource
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from myapp.models import MyModel

class MyResource(ModelResource):
    model = MyModel

urlpatterns = patterns('',
    url(r'^$', ListOrCreateModelView.as_view(resource=MyResource)),
    url(r'^(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource=MyResource)),
)

Take the example from official site, all above codes provide api, self explained document(like soap based webservice) and even sandbox to test a bit. Very convenience.

Links: http://django-rest-framework.org/

1
  • 2
    Especially the browesable interface is saving a lot of time while developing! Many other advantages, so everyone starting rest implementation should have a look. I started with tastypie, but switched completely to django-rest-framework Aug 16, 2012 at 14:22
3
votes

I am not an expert on the python world but I have been using django which is an excellent web framework and can be used to create a restful framework.

3
votes

web2py includes support for easily building RESTful API's, described here and here (video). In particular, look at parse_as_rest, which lets you define URL patterns that map request args to database queries; and smart_query, which enables you to pass arbitrary natural language queries in the URL.

2
  • The links mentioned are no longer available Feb 2, 2012 at 22:15
  • The links have been updated - try again.
    – Anthony
    Feb 3, 2012 at 15:08
2
votes

I you are using Django then you can consider django-tastypie as an alternative to django-piston. It is easier to tune to non-ORM data sources than piston, and has great documentation.

0
0
votes

I strongly recommend TurboGears or Bottle:

TurboGears:

  • less verbose than django
  • more flexible, less HTML-oriented
  • but: less famous

Bottle:

  • very fast
  • very easy to learn
  • but: minimalistic and not mature
0
votes

We are working on a framework for strict REST services, check out http://prestans.googlecode.com

Its in early Alpha at the moment, we are testing against mod_wsgi and Google's AppEngine.

Looking for testers and feedback. Thanks.

Not the answer you're looking for? Browse other questions tagged or ask your own question.