Modern Web Applications with Flask and Backbone.js. /Yaniv (Aknin Ben-Zaken)/ February 2013



Similar documents
Mobile development with Apache OFBiz. Ean Schuessler, Brainfood

Developer Tutorial Version 1. 0 February 2015

Slides from INF3331 lectures - web programming in Python

Web Development with Flask and the Raspberry Pi Leading by Example CUAUHTEMOC CARBAJAL ITESM CEM 22/04/2014

Modern Web Application Framework Python, SQL Alchemy, Jinja2 & Flask

Modern Web Development From Angle Brackets to Web Sockets

Web [Application] Frameworks

Mojolicious. Marcos Rebelo

CIS 192: Lecture 10 Web Development with Flask

Progressive Enhancement With GQuery and GWT. Ray Cromwell

Framework as a master tool in modern web development

Developing ASP.NET MVC 4 Web Applications MOC 20486

Pentesting Web Frameworks (preview of next year's SEC642 update)

Web Cloud Architecture

How To Build A Web App

Advanced Tornado TWENTYONE Advanced Tornado Accessing MySQL from Python LAB

Developing ASP.NET MVC 4 Web Applications

JavaScript Programming

Course Name: Course in JSP Course Code: P5

latest Release 0.2.6

Rapid Website Deployment With Django, Heroku & New Relic

Nupic Web Application development

Web Programming Languages Overview

Web Development Frameworks

socketio Documentation

Web Application Frameworks. Robert M. Dondero, Ph.D. Princeton University

MarkLogic Server. Reference Application Architecture Guide. MarkLogic 8 February, Copyright 2015 MarkLogic Corporation. All rights reserved.

This course provides students with the knowledge and skills to develop ASP.NET MVC 4 web applications.

Web Design Technology

Architecture Workshop

Learning Web App Development

Developing ASP.NET MVC 4 Web Applications Course 20486A; 5 Days, Instructor-led

What s really under the hood? How I learned to stop worrying and love Magento

EECS 398 Project 2: Classic Web Vulnerabilities

Drupal CMS for marketing sites

Apache Sling A REST-based Web Application Framework Carsten Ziegeler cziegeler@apache.org ApacheCon NA 2014

Advanced Web Development SCOPE OF WEB DEVELOPMENT INDUSTRY

Scalable and Efficient Web Application Architectures. Thin-clients and SQL vs. Thick-clients and NoSQL

CHOOSING THE RIGHT HTML5 FRAMEWORK To Build Your Mobile Web Application

Web Server Languages Summer Thomas A. Powell

Introducing Apache Pivot. Greg Brown, Todd Volkert 6/10/2010

Traitware Authentication Service Integration Document

Implementing Mobile Thin client Architecture For Enterprise Application

The Django web development framework for the Python-aware

White Paper On. Single Page Application. Presented by: Yatin Patel

Shipbeat Magento Module. Installation and user guide

Introduction to web development and JavaScript

Managing User Accounts and User Groups

Team Members: Christopher Copper Philip Eittreim Jeremiah Jekich Andrew Reisdorph. Client: Brian Krzys

Outline. Lecture 18: Ruby on Rails MVC. Introduction to Rails

SOA, case Google. Faculty of technology management Information Technology Service Oriented Communications CT30A8901.

A Web- based Approach to Music Library Management. Jason Young California Polytechnic State University, San Luis Obispo June 3, 2012

Design and Functional Specification

Web application Architecture

General principles and architecture of Adlib and Adlib API. Petra Otten Manager Customer Support

Avaya Inventory Management System

Credits: Some of the slides are based on material adapted from

Google Web Toolkit (GWT) Architectural Impact on Enterprise Web Application

IBM Script Portlet for WebSphere Portal Release 1.1

Web-Application Security

Integration the Web 2.0 way. Florian Daniel April 28, 2009

Web Development. How the Web Works 3/3/2015. Clients / Server

WE BUILD ONLINE SYSTEMS USEFUL WEB & MOBILE APPLICATIONS

Evaluation. Chapter 1: An Overview Of Ruby Rails. Copy. 6) Static Pages Within a Rails Application

J j enterpririse. Oracle Application Express 3. Develop Native Oracle database-centric web applications quickly and easily with Oracle APEX

Ruby on Rails is a web application framework written in Ruby, a dynamically typed programming language The amazing productivity claims of Rails is

About ZPanel. About the framework. The purpose of this guide. Page 1. Author: Bobby Allen Version: 1.1

The Web as a Client-Server System; TCP/IP intro!

Bachelor Project System (BEPsys)

Overview. In the beginning. Issues with Client Side Scripting What is JavaScript? Syntax and the Document Object Model Moving forward with JavaScript

Working with Structured Data in Microsoft Office SharePoint Server 2007 (Part1): Configuring Single Sign On Service and Database

FormAPI, AJAX and Node.js

Certified PHP/MySQL Web Developer Course

CIS 192: Lecture 10 Web Development with Flask

place/business fetch details, removefromfavorite () function, 189 search button handler bind, B BlackBerry build environment

An Oracle White Paper June RESTful Web Services for the Oracle Database Cloud - Multitenant Edition

An introduction to creating JSF applications in Rational Application Developer Version 8.0

DIPLOMA IN WEBDEVELOPMENT

Web Applications Testing

Project 2: Web Security Pitfalls

Short notes on webpage programming languages

Web Applications Come of Age

Quick Start Guide Mobile Entrée 4

Electronic Ticket and Check-in System for Indico Conferences

CLASSROOM WEB DESIGNING COURSE

RIA Technologies Comparison

Rapid Application Development. and Application Generation Tools. Walter Knesel

Introduction to FreeNAS development

Security features of ZK Framework

Transcription:

Modern Web Applications with Flask and Backbone.js /Yaniv (Aknin Ben-Zaken)/ February 2013

Web application? Modern? CGI Real Time Web C10K+; websockets; Comet Static files 2000 1990 2010 t HTML 1.0 1 st MVC Frameworks ASP; ColdFusion; PHP 1 st Browser War MSIE 6.0 ; Netscape 4.0 RESTish APIs 2 nd MVC Frameworks Django; Rails 2 nd Browser War MSIE; Firefox; Webkit; V8 Proprietary Plugins HTML5/CSS3 Adobe Flash SPA / Frontend MVC HTML4/CSS1/AJAX

MVC MVC is a design pattern Introduced in SmallTalk in the 70' Parts Model - the data View - the presentation of the data Controller - user interaction Move javascript implementations are some variation on the pattern and not pure MVC

MVC Why do we need a client side MVCish solution? A simple list and a counter example No client side data manipulation Getting the list Server 6 Client 6 HTML

MVC Why do we need a client side MVCish solution? A simple list and a counter example No client side data manipulation Sending a delete action Server Client 6

MVC Why do we need a client side MVCish solution? A simple list and a counter example No client side data manipulation Getting an updated page - List and counter are synced Server 5 Client 5 HTML

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation by dom mutation Getting the list Server 6 Client 6 HTML

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation by dom mutation Sending a delete request and getting confirmation Server Client 6 Delete Confirmation AJAX

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation by dom mutation Client side removes the item and update the counter to match Server Client 5 Update the counter The down-side of the data being mixed with the representation is that each data manipulation code must be aware of all the existing ways it is shown, and update them.

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation by dom mutation Updating every other representation of this data Server Client 5 Update the counter, AND THE OTHER LIST Suppose we want to have a thumbnail list widget in the corner, we'll have to update the delete code to update that as well.

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation by dom mutation Updating every other representation of this data Server Client 5 Update the counter, AND THE OTHER LIST Suppose we want to have a thumbnail list widget in the corner, we'll have to update the delete code to update that as well.

MVC Why do we need a client side MVCish solution? A simple list and a counter example Client side data manipulation using a model and mutiple views The server sent only data, not html. The html is built by the views. Server Model Views JSON DATA 5 AJAX After a delete, the model is changed. The views Observe the model and update themselves after a change. The model isn't aware of the different views and their implementation. Code is easier to maintain.

Web Application: concepts Backend Frontend Persistence Logic (Resource State) Pages and Assets Misc. Legacy resources UI Layout Validation Non persistent logic (Session state) Easy to get started - challenges are typically with deployment, scale, monitor, secure, etc

Web Application: roles Backend Frontend API Auth Assets Deployment Batch jobs (no views!) RESTish API Templating Browser Abstraction MVC Framework Scripting/stylesheet syntactic sugar Pixel Perfection

RESTish REST: Architectural style pioneered by Roy Fielding Often misunderstood and misimplemented Strict adherence to constraints defines RESTfulness RESTish is what we call "REST inspired" services Common principles client-server over HTTP resource oriented & uniform interface stateless (or stateleast) layered and cachable not really RESTful...

Crash course: FLSK 101 #!/usr/bin/env python from flask import Flask app = Flask( name ) @app.route('/') def hello_world(): return 'Hello World!' if name == ' main ': app.run(debug=true)

Things to keep in mind Flask is surprisingly thin Read the source, Luke Get familiar with Werkzeug Brilliant context locals are brilliant Flask in under ten lines: class Flask(_PackageBoundObject):... def wsgi_app(self, environ, start_response): with self.request_context(environ): try: response = self.full_dispatch_request() except Exception, e: rv = self.handle_exception(e) response = self.make_response(rv) return response(environ, start_response)

Crash course: FLSK 102 #!/usr/bin/env python import os from httplib import ACCEPTED, FORBIDDEN from flask import Flask, request app = Flask( name ) @app.route('/', methods=['delete']) def reboot(): if request.values.get('password') == 'secret': os.system('sudo shutdown now') return 'ok', ACCEPTED return 'no', FORBIDDEN if name == ' main ': app.run()

Crash course: FLSK 103 @app.route('/') def show_entries(): cur = g.db.execute(select_sql) ent = [dict(ttl=r[0], txt=r[1]) for r in cur. fetchall()] return render_template('show_entries.html', ent=ent) @app.route('/add', methods=['post']) def add_entry(): if not session.get('logged_in'): abort(unauthorized) g.db.execute(insert_sql, [request.form['title'], request.form['text']]) g.db.commit() flash('new entry was successfully posted') return redirect(url_for('show_entries'))

Crash course: FLSK 103 @app.route('/') def show_entries(): cur = g.db.execute(select_sql) ent = [dict(ttl=r[0], txt=r[1]) for r in cur. fetchall()] return render_template('show_entries.html', ent=ent) @app.route('/add', methods=['post']) def add_entry(): if not session.get('logged_in'): abort(unauthorized) g.db.execute(insert_sql, [request.form['title'], request.form['text']]) g.db.commit() flash('new entry was successfully posted') return redirect(url_for('show_entries')) This is server side MVC! (read: not our cup of tea)

Crash course: FLSK 103 @app.route('/user/<int:id>') def user_page(id): User.query.get_or_404(id) return render_template('user.html', user_id = id, ) {% extends "webapp.html" %} {% block head %} {{ super() }} <script type="text/javascript"> window.xx.context.user_id = {{ user_id tojson safe }}; $(function() { UserPage({el: $('.user_page')}); }); </script> <script type="text/javascript" src="{% asset "user.js" %}"></script> <link rel="stylesheet" href="{% asset "user.css" %}"/> {% endblock %} {% block body %} {{ super() }} <div class="user_page"> <div id="header_bar"><div class="logo"></div></div> </div> {% endblock %}

Crash course: FLSK 103 @app.route('/user/<int:id>') def user_page(id): User.query.get_or_404(id) return render_template('user.html', user_id = id, ) {% extends "webapp.html" %} {% block head %} {{ super() }} <script type="text/javascript"> window.xx.context.user_id = {{ user_id tojson safe }}; $(function() { UserPage({el: $('.user_page')}); }); </script> <script type="text/javascript" src="{% asset "user.js" %}"></script> <link rel="stylesheet" href="{% asset "user.css" %}"/> {% endblock %} {% block body %} {{ super() }} <div class="user_page"> <div id="header_bar"><div class="logo"></div></div> </div> {% endblock %} Complete View & Template of user page (you're not seeing much here - that's the point!)

Crash course: FLSK 103 @app.route('/user/<int:id>') def user_page(id): User.query.get_or_404(id) return render_template('user.html', user_id = id, ) {% extends "webapp.html" %} {% block head %} {{ super() }} <script type="text/javascript"> window.xx.context.user_id = {{ user_id tojson safe }}; $(function() { UserPage({el: $('.user_page')}); }); </script> <script type="text/javascript" src="{% asset "user.js" %}"></script> <link rel="stylesheet" href="{% asset "user.css" %}"/> {% endblock %} {% block body %} {{ super() }} <div class="user_page"> <div id="header_bar"><div class="logo"></div></div> </div> {% endblock %} Complete View & Template of user page (you're not seeing much here - that's the point!)

flask-assets crash course Flask extension wrapping the webassets package Declaratively define your pages' assets Assets are filtered during deployment / on the fly (development) from flask.ext.assets import Environment, Bundle from.app import app assets = Environment(app) coffee = Bundle('js/lib/lib.coffee', 'js/lib/auth.coffee', filters="coffeescript", debug=false, output="gen/base.coffee.js") js = Bundle('js/vendor/underscore.js', 'js/vendor/backbone.js', coffee output="gen/base.js", filters="yui_js") assets.register('base.js', js)

flask-assets crash course Flask extension wrapping the webassets package Declaratively define your pages' assets Assets are filtered during deployment / on the fly (development) from flask.ext.assets import Environment from utils.flaskutils import register_assets from.app import app spec = { "base.js": ('js/lib/lib.coffee', 'js/lib/auth.coffee', 'js/vendor/underscore.js', 'js/vendor/backbone.js') } register_assets(assets, spec)

flask-restful crash course "Flask-RESTful provides the building blocks for creating a great REST API" Read: "...for easily creating a decent RESTish API" Intensely down-to-business, not coupled to anything (db, etc) Highly recommended, still under development from myproject import app from flask.ext import restful api = restful.api(app) class HelloWorld(restful.Resource): def get(self): return {'hello': 'world'} api.add_resource(helloworld, '/')

flask-sqlalchemy crash course Flask extension wrapping the incredible SQLAlchemy package Every ORM I saw trades power for simplicity - SA trades very little power yet stays decently simple Great layered approach from high level ORM to declarative API for SQL from flask.ext.sqlalchemy import SQLAlchemy from.app import app db = SQLAlchemy(app) class User(db.Model): id = db.column(db.integer, primary_key=true) username = db.column(db.string(80), unique=true) def init (self, username): self.username = username def repr (self): return '<User %r>' % self.username

Two great tastes that taste great together! class Marshallable(Resource): method_decorators = (marshal_with(self.fields),) class Entity(Marshallable): def build_query(self): return self.model.query def get(self, id): return self.build_query().get_or_404(id) class UserMixin(object): fields = {"username": String} model = models.user class User(UserMixin, Entity): pass api.add_resource(user, '/api/users/<int:id>', endpoint='api_user')

Suggested project layout $ find * -maxdepth 2 vi - manage.py requirements.txt runcommands.sh backend/ api/ app.py assets.py auth.py models.py static@ templates/ views.py config/ settings.py frontend/ index/ core.coffee core.scss hello_world.jst <more pages> utils/ <more app specific code>/

Suggested project layout $ find * -maxdepth 2 vi - manage.py requirements.txt runcommands.sh backend/ api/ app.py assets.py auth.py models.py static@ templates/ views.py config/ settings.py frontend/ index/ core.coffee core.scss hello_world.jst <more pages> utils/ <more app specific code>/

Bonus slide: authentication Make sessions a resource PUT for login, DELETE for logout, GET for whoami Easy to implement with flask-login and flask-restful class Session(Resource): fields = dict(basic_user_fields) def marshal(self, user): return marshal(user, self.fields) def get(self): if current_user: return self.marshal(current_user), OK return None, NO_CONTENT def delete(self): if not current_user: return None, NO_CONTENT logout_user() return None, RESET_CONTENT @parse_with(argument('kind', required=true, choices=backends)) def put(self, params): try: user, created = backends[params.kind]() return self.marshal(user), CREATED if created else OK except InvalidAuth, error: return {"message": error.msg}, error.status

Backbone Provides small amount of useful building blocks and the rest is up to you Has a strong following and a lot of extensions are available Main parts: Model View Collection Router Events - All of the parts can be used with a pub/sub pattern using backbone events methods (*Templates) - Backbone doesn't come with templating, you can use any js templating solution. We will use underscore's templates.

Backbone The files which make up our example's frontend app: AppView.coffee Router.coffee TodoCollection.coffee TodoModel.coffee TodoView.coffee app.coffee css img jst

Backbone - Model Used for data You get listen to change events Can be have a url and be synced with the backend window.jj.todomodel = class TodoModel extends Backbone.Model defaults: title: '' completed: false toggle: -> @save { completed:!@get('completed') }

Backbone - Collection A collection is a list of models Useful events for a model add, remove, change, etc Also can be fetched or sent as whole to the server window.jj.todocollection = class TodoCollection extends Backbone.Collection model: jj.todomodel url : "/api/todos/" completed: -> return @filter((todo) -> return todo.get('completed') ) remaining: -> return @without.apply @, @completed() nextorder: -> if not @length return 1 return @last().get('order') + 1 comparator: (todo) -> return todo.get('order')

Backbone - View - single item Handles a dom element or sub-views Open for interpretation, and has many ways to use Usually will listen to a Model's changes and re-render itself when needed window.jj.todoview = class TodoView extends Backbone.View tagname: 'li' template: _.template jj.jst["todo/jst/item.jst"] events: 'click.toggle': 'togglecompleted' 'dblclick label': 'edit' 'click.destroy': 'clear' 'keypress.edit': 'updateonenter' 'blur.edit': 'close' initialize: -> @listento @model, 'change', @render @listento @model, 'destroy', @remove @listento @model, 'visible', @togglevisible User interaction Listens to model changes render: -> @$el.html @template(@model.tojson()) @$el.toggleclass 'completed', @model.get('completed') @togglevisible() @$input = @$('.edit') return @ Render the element

Backbone - View - single item togglevisible: -> @.$el.toggleclass 'hidden', @ishidden() ishidden: -> iscompleted = @model.get('completed') return (!iscompleted and (jj.app?.todofilter is 'completed')) or (iscompleted and (jj.app?.todofilter is 'active')) togglecompleted: -> @model.toggle() edit: -> @$el.addclass 'editing' @$input.focus() close: -> value = @$input.val().trim() if value @model.save { title: value } else @clear() @$el.removeclass 'editing' updateonenter: (e) -> if e.which is jj.enter_key @close() clear: -> @model.destroy() Update the model Remove the model

Backbone - View - items list We can see the view manages item views Also listens to the router for url/hash changes and updates state window.jj.appview = class AppView extends Backbone.View template: _.template jj.jst["todo/jst/app.jst"] statstemplate: _.template jj.jst["todo/jst/stats.jst"] events: 'keypress #new-todo': 'createonenter' 'click #clear-completed': 'clearcompleted' 'click #toggle-all': 'toggleallcomplete' initialize: -> @buildelement() @allcheckbox = @$('#toggle-all')[0] @$input = @$('#new-todo') @$footer = @$('#footer') @$main = @$('#main') User interaction events @listento @collection, 'add', @addone @listento @collection, 'reset', @addall @listento @collection, 'change:completed', @filterone @listento @collection, 'all', @render @initrouter() @collection.fetch() initrouter : -> @router = new jj.router() @listento @router, 'route:filterset', @updatefilter Listens to collection changes Listens to the router

Backbone - View - items list buildelement: -> @.$el.html @template() render: -> completed = @collection.completed().length remaining = @collection.remaining().length if @collection.length @$main.show() @$footer.show() @$footer.html @statstemplate({ completed: completed remaining: remaining }) @$('#filters li a').removeclass('selected').filter('[href="#/' + ( jj.app?.todofilter or '' ) + '"]').addclass('selected') else @$main.hide() @$footer.hide() @allcheckbox.checked =!remaining updatefilter : (param) -> jj.app.todofilter = param.trim() or '' @filterall() Building the main element Managing visibility according to filters addone: (todo) -> view = new jj.todoview({ model: todo }) $('#todo-list').append view.render().el addall: -> @$('#todo-list').html('') @collection.each(@addone, @)... Managing the list items rendering

Backbone - Launching it all We initialize our main view and pass to it the dom element it is responsible for and the collection In general it is easier to maintain views that don't expect dom elements to be already present or models that are on a expected global (principle of least privilege) Existing DOM: <section id="todoapp"></section> <div id="info"> <p>double-click to edit a todo</p> <p>based on the work of <a href="https://github. com/addyosmani">addy Osmani</a></p> <p>part of <a href="http://todomvc.com" >TodoMVC</a></p> <p>modified by Yaniv Ben-Zaken (@cizei)</p> </div> app.coffee code: $ -> jj.app = new jj.appview el : $('#todoapp') collection : new jj.todocollection This all the HTML and JS you have in order to launch the app. All the rest is in templates which get rendered after by code this 4 js lines launch. Backbone.history.start()

Backbone - Template Backbone come with it's own templating system There are many libraries for js-templates you can plug in and use, in most of them basically you convert a string to function which will accept a key value pairings as context and give you back an html string Item template example (using underscore.js templates): <div class="view"> <input class="toggle" type="checkbox" <%= completed? 'checked' : '' %>> <label><%- title %></label> <button class="destroy"></button> </div> <input class="edit" value="<%- title %>">

Web Application: packages Backend Frontend flask-restful flask-sqlalchemy flask-login flask-assets flask-script rq (postgres, redis, gunicorn, gevent) RESTish API Backbone.js jquery underscore.js CoffeeScript SCSS

Additional resources! flask-todo: "modern webapp" based on real code https://github.com/fusic-com/flask-todo In Flask we Trust (great Flask primer) http://ua.pycon.org/static/talks/davydenko.pdf Thoughts on RESTful API Design (don't do REST without this!) https://restful-api-design.readthedocs.org/en/latest/ Fielding on poor REST implementations (read the links, too) http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven http://roy.gbiv.com/untangled/2008/specialization Addy Osmani's TodoMVC http://addyosmani.github.com/todomvc/ Coverage of MVC history and client side solutions http: //addyosmani.com/blog/digesting-javascript-mvc-pattern-abuse-or-evolution/

Thank you! yaniv@aknin.name (@aknin) me@yaniv.bz (@cizei) (pssst: All that stuff sounds cool? is hiring! Talk to us!)