2. What is Brubeck?
• A Mongrel2 Handler
• A Web Framework and Django
• Influenced by Flask,Tornado
• A pipeline of coroutines
• Some coded opinions and a few libraries
• Backend agnostic
• Database agnostic
• No spaghetti code
Tuesday, July 17, 12
3. What is a “Mongrel2”?
• A Mongrel2 is an asynchronous web server
• Delegatesthat part to external handlers
handling
• We build
• They communicate across 2 ZeroMQ sockets
• Less processing than HTTP
• Language agnostic JSON or tnetstring
• Simple messaging via
• ZeroMQ is language agnostic, thus so is Mongrel2
Tuesday, July 17, 12
4. Mongrel2 + A Handler
Mongrel 2
Push / Pull Pub / Sub
Handler
Handler
Handler
Tuesday, July 17, 12
5. 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 ZeroMQ sockets are language agnostic
language opinion
•
• Zed chose Lua when he built Tir
• I liked his model, but I like Python too
• Lots of languages now supported
Tuesday, July 17, 12
6. Mongrel2 + Brubecks
Mongrel 2
Push / Pull Pub / Sub
Handler
Handler
Brubeck
Tuesday, July 17, 12
7. Hello world Take five!
class DemoHandler(WebMessageHandler):
def get(self):
self.set_body('Take five!')
return self.render()
urls = [('^/brubeck', DemoHandler)]
Tuesday, July 17, 12
8. 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 render(body)
Tuesday, July 17, 12
9. Brubeck: routing
Went with the usual style
class NameHandler(WebMessageHandler):
def get(self, name):
...
def name_handler(application, message, name):
...
urls = [(r'^/class/(w+)$', NameHandler),
(r'^/fun/(?Pw+)$', name_handler)]
• https://github.com/j2labs/brubeck/blob/master/demos/demo_urlargs.py
Tuesday, July 17, 12
10. Brubeck: templates
Supports: Jinja2, Mako,Tornado or Mustache
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
Tuesday, July 17, 12
11. 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
Tuesday, July 17, 12
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
Tuesday, July 17, 12
13. 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
Tuesday, July 17, 12
14. 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
Tuesday, July 17, 12
15. 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
}
Tuesday, July 17, 12
16. 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()
Tuesday, July 17, 12
17. Brubeck: autoapi
Automatic REST APIs from data models (!!)
(Ben Beecher++)
• 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
Tuesday, July 17, 12
18. Brubeck: autoapi
A Todo API
# Define Todo model
class Todo(Document):
completed = BooleanField(default=False)
deleted = BooleanField(default=False)
archived = BooleanField(default=False)
title = StringField(required=True)
...
# Add fields to handler
class TodosAPI(AutoAPIBase):
queries = DictQueryset(db_conn={})
model = Todo
# Register with Brubeck instance
app.register_api(TodosAPI)
Tuesday, July 17, 12