1. 17
  1. 7

    I prefer to let a reverse proxy like Nginx handle compression, which simplifies things quite a bit and makes one less responsibility for the app.

    1. 3

      I don’t understand why the author repeatedly mentions compression as though it were an important feature. In front of any production Python web service, I’m already going to be running an httpd just to terminate TLS. Since it’s already there it is a reasonable place to do compression too.

      1. 2

        Abstraction boundaries. Engineers can find themselves splitting functionality between their fronting proxy and their web framework, which makes changes to the setup more error prone. Wait until one day you have ancient header stripping logic in your httpd while you try to force your Python app to emit headers, but you can’t get the headers to come out. Having two sources of truth for web service logic can often be quite confusing.

        1. 1

          Been there done that and it wasn’t that hard to debug.

          Obvious in retrospect solution is to keep httpd config file in the same repo so you deploy them together. We do this with IIS configuration files on Azure at the moment at work and it works pretty smoothly.

        2. 1

          In general I agree - but might make difference on embedded devices. Although you would probably want encryption - that might be left to a vpn.

      2. 4

        I had occasion at a prior gig to build a microservice in Flask, using Connexion for OpenAPI/Swagger support. I then went on to build another project with it.

        I found that it was kinda sorta okay, but the documentation wasn’t particularly good and once we started doing anything off the beaten path–say, trying to handle multiple requests or concurrency–everything just started fighting us.

        If I had to use Python for this sort of stuff again, I’d probably follow this article’s advice or check out Quart. More likely though, I’d just go back to using Phoenix (or Plug and Cowboy) or Express/Restify.

        Also, I have not had good experience with django. I’m sure it works for some people, but I am not one of them.

        1. 1

          Also my experience. Documentation is not great and if you run into weird problems you’ll be spending a lot of time digging through source and fighting.

          Phoenix or Rails is my preference for these kind of things.

        2. 3

          Oh, this is very nice. Missing the newer micro-frsmeworks built around the new/standardized async - like fastapi or sanic.

          I feel my frustration around a flask project at work is somewhat vindicated :/

          1. 3

            +1. I did enjoy proper async in Sanic instead of the mess of handler methods called in who-knows-what order in Tornado. The author’s interpretation of “some boilerplate” in Tornado was rather charitable.

          2. 3

            I actually quite love Flask. It’s my go-to for web based projects, mainly because of its extensibility (and that I’m somewhat familiar with its internals). Trouble doing X? Fret not, for someone has abstracted that into an extension: Flask-X!

            1. 3

              I worked on professional projects with Flask (v1+) and here are two things that deserve to be mentioned :

              • Using blueprints to structure the app is pretty effective to avoid the mess. It’s somewhat like Django’s apps.
              • Very good scability with uWSGI+gevent support. It doesn’t feel too hacky because uWSGI has a special option for that. (Not more hacky than using gevent per se)

              Flask dependencies don’t collaborate together. This will hit you at least once a year when you try to upgrade and things break. Too bad request.headers from flask is a werkzeug.datastructures object and the object has changed!

              It seems very strange to me. I never had any issue upgrading Flask and its core dependencies: Jinja2 and Werkzeug. Those are written by the same authors. Maybe it’s wiser to upgrade only Flask and let pip decide which dependencies need an upgrade too.

              However, it’s true, you have to be careful with global variables.

              1. 2

                I’ve used Flask only once in a small project, but a definite +1 on using blueprints to contain the mess. They provide a very nice way to encapsulate different parts of a web application.

                1. 1

                  I guess the question is: is flask+blueprints preferable to tornado? (or maybe fastapi)?

                  I get that with bottle, at least you stay lightweight and self-contained - for better or worse.

                  1. 2

                    Blueprints are a Flask feature, not an add-on or something. So using Flask+blueprints is just using Flask.

                    I’d say Flask is suitable if you do traditional SSR-apps or hybrid SSR/SPA. If you only need a backend API or a little self-contained dashboard, then yes maybe other frameworks like Bottle or FastAPI may serve you better.

              2. 3

                I think the article is incorrect claiming Flask does not support support multi-threading or workers. As Flask is a WSGI framework it is required to let the WSGI server setup multi-threading or workers (gevent/eventlet) which it does. In addition it supports both, as can be seen when looking into the Werkzeug-local code used for the maligned Flask-globals.

                I’ll also add that Flask is exploring async support and that Quart exists as the Flask API implemented with async-await.

                1. 2

                  I’ve been using Flask for years (Django before that) and it’s my go-to for any Python HTTP service when served by UWSGI. UWSGI is great at scaling Flask and if you want compression or static files then use NGINX in front. I think the points around code organization are fair since Flask doesn’t prescribe and you have to figure it out yourself, but I don’t think a Flask codebase is guaranteed to become unorganized as more developers/code are added. At work we have a pretty large Flask codebase that has some patterns and it works pretty well. I’ve had success using multiprocessing’s thread pool executors to make HTTP requests in parallel so if you don’t have async there are ways around non-blocking. Flask’s global variables are there but I don’t see how they’re a mess? Just don’t touch them.

                  If I wanted an async Python HTTP server I’d probably choose FastAPI which is a minimal framework like Flask.

                  1. 2

                    I don’t have deep experience with Flask. I’ve written an application to handle deployments on docker swarm through an HTTP API using Flask and docker-py. I must say that I enjoyed the experience. I did not had async requirements. The project’s structure is clean and easy to work with.

                    Flask does not enforce a structure but there’s a proposed project structure in the tutorial which I find to be comprehensive for projects of any size.

                    The author paints a bleak picture about a good project.

                  2. 1

                    I used Falcon on a fairly large project, and really enjoyed it. I’ve used Flask as well, and find it “ok”.
                    I’ve had to deal with some larger twisted and tornado codebases though… still gives me nightmares years later.

                    1. 1

                      Nice post!

                      The only framework I’ve tried in production was Django. It was so smooth, that I have never felt the need to reach for others. Although, I do want to try a couple, just out of sheer curiosity.

                      1. 1

                        It’s great to see a framework comparison that includes example test cases. It’s interesting to see that Tornado eventually grew some testing tools. My experience with it (really a Twisted port, Cyclone) was pretty negative, largely for lack of any test strategy.

                        I don’t think that the section on Twisted belongs in this article. As the author notes, Twisted isn’t a web framework in the way the others are (though it does include a crufty object publishing system, twisted.web.resource, that can do the job in simple cases). Mostly it’s a low-level web server — you can use it as a WSGI container (I do so for a Django app).

                        It sounds like the author has worked on Twisted codebases that lacked unit tests. There is no swifter path to madness. Twisted is useful and powerful, but far from misuse-resistant. I’d contrast that with something like Django. Even a very badly done Django project tends to have enough structure to be salvageable. This seems analogous to the Flask vs. Bottle discussion in the article.


                        [Twisted is] no joke to upgrade either, it’s like python 2 to python 3, on top of python 2 to python 3.

                        This is completely contrary to my experience. Twisted has a strict compatibility policy and really does stick to it (this can be frustrating when contributing to the project). Hyrum’s law still applies, of course, but in my experience upgrading Twisted is trivial as long as you don’t touch private stuff.


                        I’d like to see a more substantive take on “how not to Twisted” rather than this hit piece. I mean if you’re going to spend the whole thing obsessing over a trivially-implemented thing like HTTP compression you could at least mention that Twisted does that!