brubeck: overview

22
Tuesday, July 17, 12

Upload: james-dennis

Post on 01-Sep-2014

1.204 views

Category:

Technology


3 download

DESCRIPTION

The latest version of the slides I use when I give talks on Brubeck.

TRANSCRIPT

Page 1: Brubeck: Overview

Tuesday, July 17, 12

Page 2: Brubeck: Overview

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

Tuesday, July 17, 12

Page 3: Brubeck: Overview

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

Tuesday, July 17, 12

Page 4: Brubeck: Overview

Mongrel2 + A Handler

Mongrel 2

Push / Pull Pub / Sub

HandlerHandler

Handler

Tuesday, July 17, 12

Page 5: Brubeck: Overview

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

Tuesday, July 17, 12

Page 6: Brubeck: Overview

Mongrel2 + Brubecks

Mongrel 2

Push / Pull Pub / Sub

HandlerHandler

Brubeck

Tuesday, July 17, 12

Page 7: Brubeck: Overview

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

Page 8: Brubeck: Overview

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

Page 9: Brubeck: Overview

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

Tuesday, July 17, 12

Page 10: Brubeck: Overview

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

Tuesday, July 17, 12

Page 11: Brubeck: Overview

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

Page 12: Brubeck: Overview

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

Page 13: Brubeck: Overview

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

Page 14: Brubeck: Overview

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

Page 15: Brubeck: Overview

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

Page 16: Brubeck: Overview

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

Page 17: Brubeck: Overview

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++)

Tuesday, July 17, 12

Page 18: Brubeck: Overview

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)

Tuesday, July 17, 12

Page 19: Brubeck: Overview

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"}

Tuesday, July 17, 12

Page 20: Brubeck: Overview

Todos: backbone.jsAutoAPI works great with backbone.js

( https://github.com/j2labs/todos )

Tuesday, July 17, 12

Page 21: Brubeck: Overview

bpm

$ bpm create project -n demo$ cd demo$ bpm create env$ bpm create env# Web Server...Choose one (m2 wsgi): m2# ConcurrencyChoose one (gevent eventlet): gevent# TemplatingChoose one or more (jinja2 mako tornado mustache none): jinja2...(demo) $

(brubeck project manager)

Tuesday, July 17, 12

Page 22: Brubeck: Overview

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

Tuesday, July 17, 12