Bottle: A Refreshing Web Framework

I’ve been toying with some ideas lately for a neat startup.  I know I should probably come out and give more details about it, but I want to keep my lips sealed until I have something more concrete to show for it!  Anyway… I’ve been looking at doing this entire project with Ruby, but part of this project requires me to work with a remote service that uses ZeroC Ice.  I’ve come to find out very quickly, that the Ruby support in ZeroC Ice is pretty lacking, and despite my best efforts, I can’t get them to play nice with each other (if any ZeroC developers would like to share my pain, just drop me a line).

After 2 days fighting with Ruby and Ice, I decided “What the hell, let’s give Python a spin!”  To ZeroC’s credit, their Python support is working much, much better for me.  I’ve never really written anything more than a silly FizzBuzz program in Python, but I always enjoy trial by fire, so I started digging around for a nice, thin web framework to use.  After poking around for a while, I came across a little diamond in the rough called Bottle.  Working with Bottle has been a shear joy, and I couldn’t be happier with the result.  Here’s the basic idea:

  • I have a silly Ice service that I’m interfacing with.  I can’t control this remote service, so I must find something to play nicely with Ice.
  • Ice supports a very large number of languages, but I want something that is easy to pick up and easy to implement.  I struck out with Ruby because of what is probably a bug in the Ice framework, so Python was the next logical choice (don’t cry to me about Java…eww).
  • I have a small Python web service that basically acts as a glorified wrapper around the Ice service.  This will allow me to write the front-end in Rails and just make remote calls to the Python web service.
  • I chose Bottle because getting it running in my current environment with Nginx & FastCGI was a piece of cake, and it has a very low barrier for entry.  I learned the basics and had a cheesey wrapper online within 10 minutes.  You can’t beat that!

The service itself was almost too easy.  Getting up and running within bottle was as simple as dropping one file in my project folder, and writing some amazingly simple code:

#!/usr/bin/env python
from bottle import route
import bottle 

@route('/getStuff')
def getStuff():
    # get stuff from Ice service and return it

bottle.run(server=bottle.FlupFCGIServer, port=8989, host='127.0.0.1')

Pay special attention to that last line.  Basically this spawns a FastCGI server using the python Flup I already had installed because of my Mercurial setup.  After that, all I had to do was set up Nginx to serve up the site:

########## BOTTLE SERVICE ##########
server {
    listen 80;

    server_name mybottleservice.geeksharp.com;
    gzip on;

    # Make sure we pass all requests to the bottle FastCGI process
    location / {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:8989;
        fastcgi_param DOCUMENT_ROOT /home/scott/pydev/bottle_fun/;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_param REQUEST_METHOD $request_method;
        fastcgi_param CONTENT_TYPE $content_type;
        fastcgi_param CONTENT_LENGTH $content_length;
        fastcgi_param SCRIPT_FILENAME /home/scott/pydev/bottle_fun/service.py;
    }
}

Easy, huh?  Right now I’m still in development, so I haven’t written any fancy init scripts to start and stop the Bottle service, but it won’t be too hard.  I’m pretty impressed with this tiny little framework.  It’s sure making my life a lot easier.  Cheers!

Tags:

  • http://twitter.com/Codeness George André

    Cool stuff. good work.

  • ranjan

    thanks you so much, after almost giving up i was able to get this working…unfortunately i corrupted my ubuntu and lost lot of data :( .

    thanks again

  • ranjan

    Again…one of the issue with the above config is that it does not passes parameters to bottle. I’m including nginx config from Flask framework here which forwards all params to bottle framework, hope it helps to other people
    ______________________________________________________________
    # In Nginx below config passes all params to bottle app

    location = /bottle { rewrite ^ /bottle/ last; }
    location /bottle { try_files $uri @bottle; }
    location @bottle {
        include fastcgi_params;
        fastcgi_pass  localhost:4000;
        fastcgi_split_path_info ^(/bottle)(.*)$;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        #fastcgi_pass unix:/tmp/bottle-fcgi.sock;
    }

     # And here is my  bottle app

    from bottle import route, run,response
    from bottle import FlupFCGIServer
    import bottle

    @route(“/”)
    def welcome():
        return “welcome”
    @route(‘/data’)
    def data():
        return “hello world”

    run(server=FlupFCGIServer, port=4000, host=’localhost’,reloader=True,debug=True)
    _________________________________________________________
    Hope this helps community