Notes on 'Flask for Fun and Profit'
These are some notes I’ve taken while watching Flask for Fun and Profit, a PyCon Talk by Armin Ronacher, about some best practice approaches on different topics related to Flask. I linked to the video and the slides for several sections. Later I might add a template for a Flask based API thing which contains all of these snippets.
Where does Flask come from? ▶ 📖
History
- Flask <- Werkzeug
- Werkzeug <- WSGITools
- WSGITools <- Colubrid
- Colubrid <- lots of PHP / “Pocoo”
Motivation
- trac:
- nice plugin design
- wrote low level code for dealing with webserver itself. it’s own:
- fast_cgi driver
- CGI implementation
- driver for mod_python
- there was no base transport layer.
- idea: create a “standard” implementation.
- only provide the bare minimum
Why do people like it? ▶ 📖
- API reasonates with people
- There is e.g. an Amazon Lambda in Python
- Small footprint
What it’s good at ▶ 📖
- Small, HTML heavy CRUD sites, e.g. wiki, cms, community forum
- JSON APIs
- Good for micorservices
What it’s bad at ▶ 📖
- High performance Async IO. Reason: WSGI.
- there are clones though, for e.g. twisted.
My Favourite Flask App Structure ▶ 📖
create_app
Benefits of this:
- you can create multiple
create_app
’s, e.g. another one for unit testing purposes - problem: application object is encapsulated in a function. thus put your stuff into blueprints.
register_blueprints
- accesses modules via their path. expects common structure.
Optional Contained App ▶ 📖
- Goal: Clean up the namespace. Makes sense when you’re exposing an (python?) API to others
Development Runner ▶ 📖
How to configure it?
To run this, use flask
bash command, like this:
Benefits of this (vs. app.run()
):
- The runner will not die on syntax errors.
- Less work when reloading, setup code will only run once.
- No dropped connections, because the server runs on while reloading your app.
Don’t deploy debugger!
Context Locals ▶ 📖
- Globals:
current_app
andg
objects - This splits opinions. “Global variables are terrible”. But: they still have to be hidden somewhere, e.g. connection pooling in Django.
- Since it’s needed, it could be “embraced”, so everybody sees what’s going on.
Other Context Objects ▶ 📖
- Two Contexts, four global variables for HTTP Requests:
- request context bound:
flask.request
flask.session
- app context bound:
flask.g
flask.current_app
- request context bound:
- App context tears down at the end of a request. It’s automatically created on request. This is cheap to create and not complex to understand.
- collects information for the current execution (request, cronjob, …)
- e.g. security context, language() context
Resource Management ▶ 📖
- cf. documentation.
- creates DB as soon as it’s needed
- end of request, it will be closed.
- In Flask you need to do it explicitely, opposed to Django
- Another example: User management.
JSON APIs ▶ 📖
Result Wrapper
- “I don’t use extensions […] because I want to have API endpoints to be consistent”
- Headers
- Whitespaces
- Variables
- Mimetype
- Pagination (Link vs custom headers)
- Rate Limiting Information
Response Converter ▶ 📖
API Errors ▶ 📖
Add Error Handler (I think, this should be called from create_app
?):
Demo API ▶ 📖
- Functions return nice objects that can be tested easily.
Validation / Serialization ▶ 📖
- Python is bad at this. “I hate this”
- “One that works for me: voluptuous”
voluptuous 101 ▶ 📖
voluptuousified view
- Handrolling gives you control and the error handling will be way nicer
Control the API: Pagination ▶ 📖
- Extend
ApiResult
slightly
Security! ▶ 📖
- You have to know how the context in Flask works
- You have to control the “tooling”
- You have to control where the user data comes from
- Make the code aware of the context it’s executed at.
- app with customers. each one is supposed to see customer related information.
- it get’s complicated with scaffolding, like being part of an organization
- example: fixed filter
get_available_organizations
- cf. to old PHP code that printed out strings. XSS vulnerable!
- sanitization does not really work
- you need to consider the context. where is the string used?
- e.g. tmeplate -> HTML -> will be escaped accordingly
- or: JSON Escaping (▶). Serialize it as safe as possible.
- Simplify the API
- What does the data look like? Where is it used?
Testing! ▶ 📖
- Fixtures: Run common code as part of your test, before and after you tests, automatic management.
Basic Example ▶ 📖
Example Test:
More Fixtures
Example View Test
- pytest used to do a lot of magic. It got better.
- The
assert
’s get rewritten behind the scenes
Websockets and Stuff ▶ 📖
- “You don’t do that with Flask”
I wasn’t interested so much in the rest of the talk, so I stopped taking notes.