brubeck
DESCRIPTION
TRANSCRIPT
Friday, March 30, 12
What is Brubeck?
• A Mongrel2 Handler
• A Web Framework• Influenced by Flask, Tornado and Django
• A pipeline of coroutines
• Some coded opinions and a few libraries• Backend agnostic
• Database agnostic
• No spaghetti code
Friday, March 30, 12
What is a “Mongrel2”?
• A Mongrel2 is an asynchronous web server
• Delegates handling to external handlers• We build that part
• They communicate across 2 ZeroMQ sockets• Less processing than HTTP
• Language agnostic• Simple messaging via JSON or tnetstring
• ZeroMQ is language agnostic, thus so is Mongrel2
Friday, March 30, 12
Mongrel2 + A Handler
Mongrel 2
Push / Pull Pub / Sub
HandlerHandler
Handler
Friday, March 30, 12
What is a Mongrel2 Handler?
• Processes messages from Mongrel2• Essentially, a Zed specific WSGI• There has been some dissent: Y U NO USE WSGI?
• Responds in HTTP
• A language opinion• ZeroMQ sockets are language agnostic
• Zed chose Lua when he built Tir
• I liked his model, but I like Python too
• Lots of languages now supported
Friday, March 30, 12
Mongrel2 + Brubecks
Mongrel 2
Push / Pull Pub / Sub
HandlerHandler
Brubeck
Friday, March 30, 12
Pipeline of coroutines
• Preprocessing• Maps URL to handler
• Request Handling• This is the part you write
• Postprocessing• Sends an HTTP response
Each request creates 3
Friday, March 30, 12
Hello world Take five!
class DemoHandler(WebMessageHandler): def get(self): self.set_body('Take five!') return self.render()
urls = [('^/brubeck', DemoHandler)]
Friday, March 30, 12
Hello world Take five!class DemoHandler(WebMessageHandler): def get(self): self.set_body('Take five!') return self.render()
urls = [('^/brubeck', DemoHandler)]
@app.add_route('^/brubeck', method='GET')def foo(application, message): body = 'Take five!' return http_response(body, 200, 'OK', {})
Friday, March 30, 12
Brubeck: routing
class NameHandler(WebMessageHandler): def get(self, name): ...
def name_handler(application, message, name): ...
urls = [(r'^/class/(\w+)$', NameHandler), (r'^/fun/(?P\w+)$', name_handler)]
• https://github.com/j2labs/brubeck/blob/master/demos/demo_urlargs.py
Went with the usual style
Friday, March 30, 12
Brubeck: templates
from brubeck.templating import Jinja2Rendering
class DemoHandler(WebMessageHandler, Jinja2Rendering): def get(self): context = { 'name': 'J2 D2', } return self.render_template('success.html', **context)
• https://github.com/j2labs/brubeck/blob/master/demos/demo_jinja2.py
• https://github.com/j2labs/brubeck/blob/master/demos/demo_mustache.py
Supports: Jinja2, Mako, Tornado or Mustache
Friday, March 30, 12
Brubeck: auth (pt 1)• Simple example, using `web_authenticated` decorator:
class DemoHandler(..., UserHandlingMixin): @web_authenticated def get(self): context = { 'name': self.current_user.username, } return self.render_template('some.html', **context)
• Also supports secure cookies
• Routes users to login template
• https://github.com/j2labs/brubeck/blob/master/demos/demo_login.py
Friday, March 30, 12
Brubeck: auth (pt 2)class BaseHandler(..., UserHandlingMixin): def get_current_user(self): user = None secret=self.application.cookie_secret user_id = self.get_cookie('user_id', secret=secret) if user_id: return load_user(self.db_conn, username=user_id) else: username = self.get_argument('username') password = self.get_argument('password') if username: user = load_user(self.db_conn, username=username) if not user or not user.check_password(password): return return user
Friday, March 30, 12
Brubeck: user• This what a Brubeck user model looks like
class User(Document): username = StringField(max_length=30, required=True) password = StringField(max_length=128) is_active = BooleanField(default=False) last_login = LongField(default=curtime) date_joined = LongField(default=curtime) ...
• Uses UUID for id field
• Could use Mongo’s ObjectID if you prefer that
• https://github.com/j2labs/brubeck/blob/master/brubeck/models.py
Friday, March 30, 12
Brubeck: data validation• Validation is easy
>>> from brubeck.models import User>>> u = User(username='jd', is_active=True)>>> u.set_password('foo')>>> u.validate()>>> u.username = True>>> u.validate()Traceback (most recent call last):...dictshield.base.ShieldException: Invalid value - username:True
Friday, March 30, 12
Databaseless modeling• This what a Brubeck user looks like as Python
>>> user_instance.to_python(){ '_types': ['User'], '_cls': 'User', 'username': u'jd', 'is_active': False, 'last_login': 1311718487532L, 'password': u'bcrypt|||salt|||hash', 'date_joined': 1311718487532L}
Friday, March 30, 12
Databaseless modeling• Persistence details are up to you
# Mongo>>> db.users.save(u.to_python())
# Riak>>> user = bucket.new('user_key', data=u.to_python()) >>> user.store()
# Memcached>>> mc["user_key"] = u.to_json()
Friday, March 30, 12
Brubeck: autoapi
• Define a DictShield document (our model)
• Define a QuerySet - Implements persistence
• Dictionary based queryset is provided
• Redis, Mongo and MySQL on the way
• Subclass AutoAPIBase• Attach your model as `model`
• Attach your queryset as `queries`
• Register API for model in a Brubeck instance
Automatic REST APIs from data models (!!)(Ben Beecher++)
Friday, March 30, 12
Brubeck: autoapiA Todo API
# Define Todo modelclass Todo(Document): completed = BooleanField(default=False) deleted = BooleanField(default=False) archived = BooleanField(default=False) title = StringField(required=True) ...
# Add fields to handlerclass TodosAPI(AutoAPIBase): queries = DictQueryset(db_conn={}) model = Todo
# Register with Brubeck instanceapp.register_api(TodosAPI)
Friday, March 30, 12
Brubeck: autoapi$ curl -f \ -X POST \ -H "content-type: application/json" \ -d '{"text": "Watch more bsg", "order": 1}' \ http://localhost:6767/todo/
{ "_cls": "Todo", "_id": "111b4bb7-55f5-441b-ba25-c7a4fd99442c", "_types": [ "Todo" ], "done": false, "order": 1, "text": "Watch more bsg"}
Friday, March 30, 12
Todos: backbone.jsAutoAPI works great with backbone.js
( https://github.com/j2labs/todos )
Friday, March 30, 12
Questions ??
Brubeck: http://brubeck.ioCode: https://github.com/j2labs/brubeck
Mongrel2: http://mongrel.orgDictShield: https://github.com/j2labs/dictshield
Gevent: http://gevent.orgEventlet: http://eventlet.net
Friday, March 30, 12