Construindo aplicações de grande porte com o Flask

Quem sou?

Esta palestra não é

Sobre o Flask

DENIED

DENIED

Tópicos principais

Organização e criação de views

Hello world!

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Hello world!

Parece bom, não?! Mas ...

Aceitando múltiplos métodos HTTP

from flask import Flask, request
app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def hello():
    if request.method == "GET":
        return "Hello World, with GET!"
    if request.method == "POST":
        return "Hello World, with POST!"

Aceitando múltiplos métodos HTTP

Hmm... Talvez possa ficar melhor...

Class-based views

from flask import Flask
from flask.views import MethodView
app = Flask(__name__)

class HelloView(MethodView):
    def get(self):
        return "Hello World, with GET, " \
               "from a class-based view!"
    def post(self):
        return "Hello World, with POST, " \
               "from a class-based view!"

app.add_url_rule('/',
    view_func=HelloView.as_view('hello'),
    methods=["GET", "POST"])

Class-based views

E que tal reaproveitar o código?!

Class-based views com mixin

from flask import Flask
from flask.views import MethodView
app = Flask(__name__)

class GetMixin(object):
    def get(self):
        return "Hello World, with GET, " \
               "from a mixin!"

class HelloView(MethodView, GetMixin):
    def post(self):
        return "Hello World, with POST, " \
               "from a class-based view!"

app.add_url_rule('/',
    view_func=HelloView.as_view("hello"),
    methods=["GET", "POST"])

Class-based views com mixin

Uso de blueprints e factories

Blueprint básico

from flask import Flask, Blueprint
app = Flask(__name__)
bp = Blueprint("views", __name__)

@bp.route("/")
def hello():
    return "Hello World from a blueprint!"

app.register_blueprint(bp, url_prefix="/")

Blueprint básico

Blueprint inicializado com app factory

from flask import Flask, Blueprint
bp = Blueprint("views", __name__)

@bp.route("/")
def hello():
    return "Hello World from a blueprint, " \
           "with an app factory!"

def create_app():
    app = Flask(__name__)
    app.register_blueprint(bp, url_prefix="/")
    return app

Blueprint inicializado com app factory

Isolando testes com app factories

import unittest
from flask import Flask, Blueprint, current_app
bp = Blueprint("views", __name__)

@bp.route("/")
def hello():
    return "Hello %s" % current_app.config["NAME"]

def create_app():
    app = Flask(__name__)
    app.register_blueprint(bp, url_prefix="/")
    return app

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app()
        self.app.config["NAME"] = "foo"

    def test_foo(self):
        rv = self.app.test_client().get("/")
        self.assertIn("Hello foo", rv.data)

if __name__ == "__main__":
    unittest.main()

Isolando testes com app factories

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app()
        self.app.config["NAME"] = "foo"

    def test_foo(self):
        rv = self.app.test_client().get("/")
        self.assertIn("Hello foo", rv.data)

Manipulação de exceções

Retornando um status code HTTP

from flask import Flask, abort
app = Flask(__name__)

@app.route("/")
def hello():
    abort(412)

Retornando um status code HTTP

Retornando um status code HTTP a partir de exceções

from flask import Flask
from werkzeug.exceptions import PreconditionFailed
app = Flask(__name__)

@app.route("/")
def hello():
    raise PreconditionFailed

Retornando um status code HTTP a partir de exceções

Exceções HTTP com descrição customizada

from flask import Flask
from werkzeug.exceptions import PreconditionFailed
app = Flask(__name__)

class MyPreconditionFailed(PreconditionFailed):
    description = 'Ooops... the precondition failed! :P'

@app.route("/")
def hello():
    raise MyPreconditionFailed

Exceções HTTP com descrição customizada

Error handlers customizados

from flask import Flask, abort, jsonify
app = Flask(__name__)

@app.errorhandler(412)
def handler(error):
    return jsonify(status_code=error.code,
                   description=error.description)

@app.route("/")
def hello():
    abort(412)

Error handlers customizados

Exemplos de uso

Perguntas?

/

#